First try of actually working code

This commit is contained in:
amki 2019-10-17 04:23:13 +02:00
parent 7479534a9f
commit 6885d6b6b9
12 changed files with 203 additions and 167 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

Binary file not shown.

View File

@ -4,7 +4,9 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.ServiceModel.Syndication;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Xml;
@ -30,6 +32,8 @@ namespace DiscoBot.gsmeet
private static readonly string ApplicationName = "DiscoBot";
private SheetsService service;
private Dictionary<string, GSMeetingTimers> meetingTimers = new Dictionary<string, GSMeetingTimers>();
public GSMeet(SocketGuild guild)
@ -49,21 +53,11 @@ namespace DiscoBot.gsmeet
ApplicationName = ApplicationName
});
gsmeetContext.GSheets.Include(s => s.NotifiedEvents).Load();
gsmeetContext.GSheets.Include(s => s.NotifiedUsers).Load();
foreach (var f in gsmeetContext.GSheets)
{
if(f.NotifiedUsers == null)
{
f.NotifiedUsers = new List<GSMeetUserNotification>();
}
if(f.NotifiedEvents == null)
{
f.NotifiedEvents = new List<GSMeetEventNotification>();
}
InitializeSheet(f);
HandleSheetCheck(f);
var gssheet = new GSSheet(f);
InitializeSheet(gssheet);
HandleSheetCheck(gssheet);
}
Commands.Add("gsmeetadd", HandleGSMeetAddCommand);
@ -72,21 +66,21 @@ namespace DiscoBot.gsmeet
Commands.Add("gsmeetdebug", HandleGSMeetDebugCommand);
}
private Task InitializeSheet(DBSheet sheet)
private Task InitializeSheet(GSSheet sheet)
{
Console.WriteLine("Found sheet " + sheet.Name);
Timer timer = new Timer(sheet.CheckInterval.TotalMilliseconds);
Console.WriteLine("Found sheet " + sheet.Db.Name);
Timer timer = new Timer(sheet.Db.CheckInterval.TotalMilliseconds);
timer.AutoReset = true;
timer.Elapsed += async (sender, e) =>
{
await Task.Run(() => HandleSheetCheck(sheet));
};
timer.Start();
timers.Add(sheet.Name, timer);
timers.Add(sheet.Db.Name, timer);
return Task.CompletedTask;
}
private Task DeinitializeSheets(DBSheet sheet)
private Task DeinitializeSheets(GSSheet sheet)
{
/*
Timer t = timers[feed.Name];
@ -96,125 +90,103 @@ namespace DiscoBot.gsmeet
return Task.CompletedTask;
}
private Task ParseGSMeetSheet(GSMeetSheetData sheetData, IList<IList<object>> values)
private GSMeeting ParseMeeting(SocketTextChannel c, IList<IList<object>> values)
{
var daterow = values[1];
var time = TimeSpan.Parse((string)daterow[0]);
var events = new List<DateTimeOffset>();
var users = new List<GSMeetUser>();
for (int i = 2; i < daterow.Count; ++i)
var meeting = new GSMeeting();
var dateRow = values[1];
var time = TimeSpan.Parse((string)dateRow[0]);
var idString = "";
for (int i = 2; i < dateRow.Count; ++i)
{
var col = daterow[i];
var col = dateRow[i];
var d = DateTimeOffset.Parse((string)col, null, DateTimeStyles.AssumeUniversal);
events.Add(d + time);
var dateTime = d + time;
idString += dateTime.ToString("o");
meeting.Dates.Add(dateTime);
}
for (int i = 2; i < values.Count; ++i)
for(int i=2;i<values.Count;++i)
{
var row = values[i];
GSMeetUser u = new GSMeetUser();
var u = new GSMeetingUser();
u.DiscordTag = (string)row[0];
try {
u.User = guild.Users.Where(gu => (gu.Username + "#" + gu.DiscriminatorValue) == u.DiscordTag).Single();
} catch(InvalidOperationException e)
{
// Too spammy, do something about it? Don't rely on u.User
//c.SendMessageAsync("Could not find User "+ u.DiscordTag+" in Discord, cannot mention.");
}
u.Name = (string)row[1];
for (int j = 2; j < row.Count; ++j)
{
var str = (string)row[j];
if(str != "")
u.Signups.Add(events[j - 2], str);
u.Signups.Add(str);
}
users.Add(u);
// Fill the empty columns that the api skipped
while(u.Signups.Count < meeting.Dates.Count)
{
u.Signups.Add("");
}
meeting.Users.Add(u);
}
sheetData.Dates = events;
sheetData.Users = users;
return Task.CompletedTask;
var sha1 = new SHA1CryptoServiceProvider();
var binHash = sha1.ComputeHash(Encoding.ASCII.GetBytes(idString));
var hash = BitConverter.ToString(binHash).Replace("-", string.Empty);
meeting.Id = hash;
return meeting;
}
private async Task SignupNotify(SocketTextChannel chan, GSMeetSheetData sheetData)
private async Task<List<GSMeeting>> ParseGSMeetSheet(GSSheet sheet, IList<IList<object>> values)
{
foreach(var date in sheetData.Dates)
SocketTextChannel c = guild.Channels.Where(g => g.Id == sheet.Db.Channel).Single() as SocketTextChannel;
int meetStart = -1;
var val = values as List<IList<object>>;
var meetings = new List<GSMeeting>();
for (var i=0;i<values.Count;++i)
{
if(DateTimeOffset.UtcNow + new TimeSpan(4,0,0,0) > date && date > DateTimeOffset.UtcNow)
var row = values[i] as List<object>;
if(row.Count < 1)
{
await chan.SendMessageAsync("I should signup notify for " + date);
foreach (var user in sheetData.Users)
continue;
}
if((string)row[0] == "Raid")
{
if(meetStart == -1)
{
if (!user.Signups.ContainsKey(date))
{
bool doNotify = true;
foreach(var notification in sheetData.Sheet.NotifiedUsers)
{
if(notification.Date == date && notification.DiscordTag == user.DiscordTag)
{
Console.WriteLine("User already notified.");
doNotify = false;
break;
}
}
if (doNotify)
{
await chan.SendMessageAsync("Hey " + user.DiscordTag + " please sign up for our raid on " + date);
var n = new GSMeetUserNotification(user.DiscordTag, date);
sheetData.Sheet.NotifiedUsers.Add(n);
}
}
meetStart = i;
} else
{
meetings.Add(ParseMeeting(c, val.GetRange(meetStart,(i-meetStart-2))));
meetStart = i;
}
}
}
// Last meeting starts with Raid, thus sets meetStart but no other meeting finishes it, so parse last rows as last meeting
meetings.Add(ParseMeeting(c, val.GetRange(meetStart, (values.Count - meetStart))));
Console.WriteLine("I parsed " + meetings.Count + " meetings from the sheet.");
return meetings;
}
private async Task RaidNotify(SocketTextChannel chan, GSMeetSheetData sheetData)
private async Task HandleSheetCheck(GSSheet sheet)
{
foreach (var date in sheetData.Dates)
{
if (DateTimeOffset.UtcNow + new TimeSpan(2,0,0,0) > date)
{
await chan.SendMessageAsync("I should raid notify for " + date);
//
}
}
}
private Task CleanupNotifyDB(GSMeetSheetData sheetData)
{
for(var i=sheetData.Sheet.NotifiedEvents.Count-1;i>=0;i--)
{
var n = sheetData.Sheet.NotifiedEvents[i];
if(DateTimeOffset.UtcNow > n.Date)
{
sheetData.Sheet.NotifiedEvents.Remove(n);
gsmeetContext.Entry(n).State = EntityState.Deleted;
}
}
for (var i = sheetData.Sheet.NotifiedUsers.Count - 1; i >= 0; i--)
{
var n = sheetData.Sheet.NotifiedUsers[i];
if (DateTimeOffset.UtcNow > n.Date)
{
sheetData.Sheet.NotifiedUsers.Remove(n);
gsmeetContext.Entry(n).State = EntityState.Deleted;
}
}
gsmeetContext.SaveChanges();
return Task.CompletedTask;
}
private async Task HandleSheetCheck(DBSheet sheet)
{
var sheetData = new GSMeetSheetData(sheet);
SocketTextChannel c = guild.Channels.Where(g => g.Id == sheet.Channel).Single() as SocketTextChannel;
await c.SendMessageAsync("Checking sheet " + sheet.Id + " :3");
var values = FetchRangeFromSheet(sheet.Id, $"{sheet.SheetName}!A1:I10");
SocketTextChannel c = guild.Channels.Where(g => g.Id == sheet.Db.Channel).Single() as SocketTextChannel;
Console.WriteLine("Checking sheet " + sheet.Db.Id + " :3");
var values = FetchRangeFromSheet(sheet.Db.Id, $"{sheet.Db.SheetName}!A:I");
if (values == null || values.Count < 1)
{
await c.SendMessageAsync("No values found.");
Console.WriteLine("No values found.");
}
await ParseGSMeetSheet(sheetData, values);
await c.SendMessageAsync("Parsed sheet " + sheet.Id);
await SignupNotify(c, sheetData);
await RaidNotify(c, sheetData);
gsmeetContext.SaveChanges();
CleanupNotifyDB(sheetData);
var meetings = await ParseGSMeetSheet(sheet, values);
foreach(var meeting in meetings)
{
if(!sheet.Timers.ContainsKey(meeting.Id))
{
sheet.Timers.Add(meeting.Id, new GSMeetingTimers());
}
sheet.Timers[meeting.Id].UpdateTimers(c, meeting);
}
Console.WriteLine("Parsed sheet " + sheet.Db.Id);
/*
var str = "";
foreach (var row in values)
@ -249,7 +221,8 @@ namespace DiscoBot.gsmeet
try
{
gsmeetContext.SaveChanges();
InitializeSheet(sheet);
var gssheet = new GSSheet(sheet);
InitializeSheet(gssheet);
msg.Channel.SendMessageAsync("Sheet " + sheet.Name + " with id " + sheet.Id + " saved.");
}
catch (InvalidOperationException)
@ -313,27 +286,7 @@ namespace DiscoBot.gsmeet
private Task HandleGSMeetDebugCommand(SocketMessage msg, string[] parameters)
{
var gchan = msg.Channel as IGuildChannel;
string name = parameters[1];
string sheetId = parameters[2];
string sheetName = parameters[3];
var values = FetchRangeFromSheet(sheetId, $"{sheetName}!A1:I10");
if(values == null || values.Count < 1)
{
msg.Channel.SendMessageAsync("No values found.");
return Task.CompletedTask;
}
var str = "";
foreach(var row in values)
{
foreach(var col in row)
{
str += col + "| ";
}
str += "\n";
}
msg.Channel.SendMessageAsync("Result: "+str);
msg.Channel.SendMessageAsync("Username: "+msg.Author.Username+"#"+msg.Author.DiscriminatorValue);
return Task.CompletedTask;
}

View File

@ -6,6 +6,7 @@ using System.Timers;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations.Schema;
using Discord.WebSocket;
namespace DiscoBot.gsmeet
{
@ -34,53 +35,40 @@ namespace DiscoBot.gsmeet
public ulong Channel { get; set; }
public TimeSpan CheckInterval { get; set; }
public DateTimeOffset LastChecked { get; set; }
public List<GSMeetEventNotification> NotifiedEvents { get; set; }
public List<GSMeetUserNotification> NotifiedUsers { get; set; }
}
public class GSMeetEventNotification
public class GSSheet
{
[ScaffoldColumn(false)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public long Id { get; set; }
public DateTimeOffset Date { get; set; }
}
public class GSMeetUserNotification
{
public GSMeetUserNotification(string discordTag, DateTimeOffset date)
public GSSheet(DBSheet db)
{
this.DiscordTag = discordTag;
this.Date = date;
this.Db = db;
this.Timers = new Dictionary<string, GSMeetingTimers>();
}
public DBSheet Db { get; set; }
public Dictionary<string, GSMeetingTimers> Timers { get; set; }
}
public class GSMeetingUser
{
public GSMeetingUser()
{
this.Signups = new List<string>();
}
[ScaffoldColumn(false)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public long Id { get; set; }
public string DiscordTag { get; set; }
public DateTimeOffset Date { get; set; }
public SocketGuildUser User { get; set; }
public string Name { get; set; }
public List<string> Signups { get; set; }
}
public class GSMeetSheetData
public class GSMeeting
{
public GSMeetSheetData(DBSheet sheet)
public GSMeeting()
{
this.Sheet = sheet;
this.Users = new List<GSMeetingUser>();
this.Dates = new List<DateTimeOffset>();
}
public DBSheet Sheet { get; set; }
public List<GSMeetUser> Users { get; set; }
public string Id { get; set; }
public List<GSMeetingUser> Users { get; set; }
public List<DateTimeOffset> Dates { get; set; }
}
public class GSMeetUser
{
public GSMeetUser()
{
this.Signups = new Dictionary<DateTimeOffset, string>();
}
public string DiscordTag { get; set; }
public string Name { get; set; }
public Dictionary<DateTimeOffset, string> Signups { get; set; }
}
}

View File

@ -0,0 +1,95 @@
using Discord.WebSocket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
namespace DiscoBot.gsmeet
{
public class GSMeetingTimers
{
private List<TimeSpan> WarningTimes = new List<TimeSpan> {
new TimeSpan(2, 0, 0, 0),
new TimeSpan(1, 0, 0, 0) };
private List<TimeSpan> UserTimes = new List<TimeSpan> {
new TimeSpan(7, 0, 0, 0),
new TimeSpan(6, 0, 0, 0),
new TimeSpan(5, 0, 0, 0),
new TimeSpan(4, 0, 0, 0),
new TimeSpan(3, 0, 0, 0) };
private Dictionary<DateTimeOffset, GSEventTimers> events = new Dictionary<DateTimeOffset, GSEventTimers>();
public GSMeetingTimers()
{
}
public void UpdateTimers(SocketTextChannel chan, GSMeeting meeting)
{
for(var i=0;i<meeting.Dates.Count;++i)
{
var date = meeting.Dates[i];
// Keep this so we can use it to pick from user.Signups later! (async)
var idx = i;
GSEventTimers evt;
if(events.ContainsKey(date))
{
evt = events[date];
} else
{
evt = new GSEventTimers();
events.Add(date, evt);
}
foreach(var t in evt.UserTimers)
{
t.Dispose();
}
evt.UserTimers = new List<Timer>();
foreach(var ts in UserTimes)
{
var when = date - ts;
if(when < DateTimeOffset.Now)
{
continue;
}
Console.WriteLine("Setting a timer for " + when + " for evt " + date);
var whents = when - DateTimeOffset.Now;
// Debug resolve timers after 30s
//Timer t = new Timer(new TimeSpan(0, 0, 30).TotalMilliseconds);
Timer t = new Timer(whents.TotalMilliseconds);
t.AutoReset = false;
var users = meeting.Users;
t.Elapsed += async (sender, e) =>
{
foreach(var user in users)
{
if(user.Signups[idx] != "1" && user.Signups[idx] != "0" && user.Signups[idx] != "0.5")
{
if(user.User != null) {
await chan.SendMessageAsync("Hey " + user.User.Mention + " could you please sign up for our raid on " + date + "?");
} else
{
await chan.SendMessageAsync("Hey " + user.Name + " could you please sign up for our raid on " + date + "?");
}
}
}
};
t.Start();
evt.UserTimers.Add(t);
}
}
}
}
public class GSEventTimers
{
public GSEventTimers()
{
this.UserTimers = new List<Timer>();
this.WarningTimers = new List<Timer>();
}
public List<Timer> UserTimers { get; set; }
public List<Timer> WarningTimers { get; set; }
}
}