You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

356 lines
13 KiB

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.ServiceModel.Syndication;
using System.Threading.Tasks;
using System.Timers;
using System.Xml;
using Discord;
using Discord.WebSocket;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Sheets.v4;
using Microsoft.EntityFrameworkCore;
namespace DiscoBot.gsmeet
{
public class GSMeet : IModule
{
string IModule.Name { get => "GSMeet"; set => throw new NotImplementedException(); }
private SocketGuild guild;
private GSMeetContext gsmeetContext;
private Dictionary<string, Timer> timers = new Dictionary<string, Timer>();
private List<WebSocket> webSockets = new List<WebSocket>();
public Dictionary<string, Func<SocketMessage, string[], Task>> Commands { get; set; } = new Dictionary<string, Func<SocketMessage, string[], Task>>();
private static readonly string[] Scopes = { SheetsService.Scope.Spreadsheets };
private static readonly string ApplicationName = "DiscoBot";
private SheetsService service;
public GSMeet(SocketGuild guild)
{
this.guild = guild;
gsmeetContext = new GSMeetContext(guild.Id);
gsmeetContext.Database.EnsureCreated();
GoogleCredential credential;
using(var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream).CreateScoped(Scopes);
}
service = new SheetsService(new Google.Apis.Services.BaseClientService.Initializer()
{
HttpClientInitializer = credential,
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);
}
Commands.Add("gsmeetadd", HandleGSMeetAddCommand);
Commands.Add("gsmeetdel", HandleGSMeetDelCommand);
Commands.Add("gsmeetlist", HandleGSMeetListCommand);
Commands.Add("gsmeetdebug", HandleGSMeetDebugCommand);
}
private Task InitializeSheet(DBSheet sheet)
{
Console.WriteLine("Found sheet " + sheet.Name);
Timer timer = new Timer(sheet.CheckInterval.TotalMilliseconds);
timer.AutoReset = true;
timer.Elapsed += async (sender, e) =>
{
await Task.Run(() => HandleSheetCheck(sheet));
};
timer.Start();
timers.Add(sheet.Name, timer);
return Task.CompletedTask;
}
private Task DeinitializeSheets(DBSheet sheet)
{
/*
Timer t = timers[feed.Name];
t.Stop();
timers.Remove(feed.Name);
*/
return Task.CompletedTask;
}
private Task ParseGSMeetSheet(GSMeetSheetData sheetData, 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 col = daterow[i];
var d = DateTimeOffset.Parse((string)col, null, DateTimeStyles.AssumeUniversal);
events.Add(d + time);
}
for (int i = 2; i < values.Count; ++i)
{
var row = values[i];
GSMeetUser u = new GSMeetUser();
u.DiscordTag = (string)row[0];
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);
}
users.Add(u);
}
sheetData.Dates = events;
sheetData.Users = users;
return Task.CompletedTask;
}
private async Task SignupNotify(SocketTextChannel chan, GSMeetSheetData sheetData)
{
foreach(var date in sheetData.Dates)
{
if(DateTimeOffset.UtcNow + new TimeSpan(4,0,0,0) > date && date > DateTimeOffset.UtcNow)
{
await chan.SendMessageAsync("I should signup notify for " + date);
foreach (var user in sheetData.Users)
{
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);
}
}
}
}
}
}
private async Task RaidNotify(SocketTextChannel chan, GSMeetSheetData sheetData)
{
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)
{
/*
foreach(var n in sheetData.Sheet.NotifiedEvents)
{
if(DateTimeOffset.UtcNow > n.Date)
{
sheetData.Sheet.NotifiedEvents.Remove(n);
}
}
foreach (var n in sheetData.Sheet.NotifiedUsers)
{
if (DateTimeOffset.UtcNow > n.Date)
{
sheetData.Sheet.NotifiedUsers.Remove(n);
}
}
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");
if (values == null || values.Count < 1)
{
await c.SendMessageAsync("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 str = "";
foreach (var row in values)
{
foreach (var col in row)
{
str += col + "| ";
}
str += "\n";
}
c.SendMessageAsync("Result: " + str);
*/
}
private Task HandleGSMeetAddCommand(SocketMessage msg, string[] parameters)
{
var gchan = msg.Channel as IGuildChannel;
string name = parameters[1];
string sheetId = parameters[2];
string sheetName = parameters[3];
try
{
int timeSec = Int32.Parse(parameters[4]);
DBSheet sheet = new DBSheet();
sheet.Channel = gchan.Id;
sheet.Name = name;
sheet.Id = sheetId;
sheet.SheetName = sheetName;
sheet.LastChecked = DateTimeOffset.Now;
sheet.CheckInterval = new TimeSpan(0, 0, timeSec);
gsmeetContext.GSheets.Add(sheet);
try
{
gsmeetContext.SaveChanges();
InitializeSheet(sheet);
msg.Channel.SendMessageAsync("Sheet " + sheet.Name + " with id " + sheet.Id + " saved.");
}
catch (InvalidOperationException)
{
msg.Channel.SendMessageAsync("Unable to save sheet feed.");
}
}
catch (FormatException)
{
msg.Channel.SendMessageAsync("Unable to save sheet. Invalid check time.");
}
return Task.CompletedTask;
}
private Task HandleGSMeetListCommand(SocketMessage msg, string[] parameters)
{
/*
List<RssFeed> feeds = rssContext.RssFeeds.Where(f => f.Channel == msg.Channel.Id).ToList();
List<string> m = new List<string>();
m.Add("Feeds for this channel are:");
m.Add("Name | URL | CheckInterval | LastChecked");
msg.Channel.SendMessageAsync(string.Join("\n", m));
m = new List<string>();
int cnt = 0;
foreach (var f in feeds)
{
m.Add("- " + f.Name + " | " + f.Url + " | " + f.CheckInterval + " | " + f.LastChecked);
cnt++;
if(cnt > 4)
{
cnt = 0;
msg.Channel.SendMessageAsync(string.Join("\n", m));
}
}
if(cnt > 0)
msg.Channel.SendMessageAsync(string.Join("\n", m));
*/
return Task.CompletedTask;
}
private Task HandleGSMeetDelCommand(SocketMessage msg, string[] parameters)
{
/*
var gchan = msg.Channel as IGuildChannel;
string name = parameters[1];
try
{
RssFeed f = rssContext.RssFeeds.Where(f => f.Name == name).Single();
rssContext.Remove(f);
rssContext.SaveChanges();
DeinitializeFeed(f);
msg.Channel.SendMessageAsync("Removed feed " + f.Name);
} catch(InvalidOperationException)
{
msg.Channel.SendMessageAsync("Could not find feed " + name);
}
*/
return Task.CompletedTask;
}
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);
return Task.CompletedTask;
}
private IList<IList<object>> FetchRangeFromSheet(string sheetId, string range)
{
var request = service.Spreadsheets.Values.Get(sheetId, range);
var response = request.Execute();
return response.Values;
}
public void Initialize()
{
Console.WriteLine("Initializing gsmeet...");
}
public async Task OnNewWebSocketAsync(WebSocket ws, TaskCompletionSource<object> tcs)
{
Console.WriteLine("Calendar " + guild.Id + " has a new websocket.");
webSockets.Add(ws);
}
}
}