public async Task StartAsync() { if (_alive) { return; } _alive = true; _stop = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); var lastStartTime = DateTime.Now; _work = Task.Run(async() => { while (!_stop.Task.IsCompleted) { var now = DateTime.Now; if (lastStartTime.Minute != now.Minute && now.Minute % _minutes == 0) { lastStartTime = now; _ = Task.Run(async() => { await Task.Delay(_offset); OnTime?.Invoke(new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0)); }); } if (await Task.WhenAny(Task.Delay(900), _stop.Task) == _stop.Task) { break; } } }); await Task.CompletedTask; }
public void ParseReply(string[] tokens) { ReplyCode code = (ReplyCode)int.Parse(tokens[1], CultureInfo.InvariantCulture); tokens[3] = RemoveLeadingColon(tokens[3]); switch (code) { //Messages sent upon successful registration case ReplyCode.RPL_WELCOME: case ReplyCode.RPL_YOURESERVICE: OnRegistered.Fire(this, new EventArgs()); break; case ReplyCode.RPL_MOTDSTART: case ReplyCode.RPL_MOTD: OnMotd?.Invoke(CondenseStrings(tokens, 3), false); break; case ReplyCode.RPL_ENDOFMOTD: OnMotd?.Invoke(CondenseStrings(tokens, 3), true); break; case ReplyCode.RPL_ISON: OnIson?.Invoke(tokens[3]); break; case ReplyCode.RPL_NAMREPLY: ProcessNamesReply(tokens, false); break; case ReplyCode.RPL_ENDOFNAMES: ProcessNamesReply(tokens, true); break; case ReplyCode.RPL_LIST: tokens[5] = RemoveLeadingColon(tokens[5]); OnList?.Invoke( tokens[3], int.Parse(tokens[4], CultureInfo.InvariantCulture), CondenseStrings(tokens, 5), false); break; case ReplyCode.RPL_LISTEND: OnList?.Invoke("", 0, "", true); break; case ReplyCode.ERR_NICKNAMEINUSE: case ReplyCode.ERR_NICKCOLLISION: tokens[4] = RemoveLeadingColon(tokens[4]); OnNickError.Fire(this, new NickErrorEventArgs(tokens[3], CondenseStrings(tokens, 4))); //Trace.WriteLine("Nick collision", "IRC"); break; case ReplyCode.RPL_NOTOPIC: OnError.Fire(this, new ErrorMessageEventArgs(code, CondenseStrings(tokens, 3))); break; case ReplyCode.RPL_TOPIC: tokens[4] = RemoveLeadingColon(tokens[4]); OnRecieveTopic?.Invoke(tokens[3], CondenseStrings(tokens, 4)); break; case ReplyCode.RPL_INVITING: OnInviteSent.Fire(this, new InviteEventArgs(tokens[3], tokens[4])); break; case ReplyCode.RPL_AWAY: OnAway.Fire(this, new AwayEventArgs(tokens[3], RemoveLeadingColon(CondenseStrings(tokens, 4)))); break; case ReplyCode.RPL_WHOREPLY: User user = new User(tokens[7], tokens[4], tokens[5]); OnWho?.Invoke( user, tokens[3], tokens[6], tokens[8], int.Parse(RemoveLeadingColon(tokens[9]), CultureInfo.InvariantCulture), tokens[10], false); break; case ReplyCode.RPL_ENDOFWHO: OnWho?.Invoke(User.Empty, "", "", "", 0, "", true); break; case ReplyCode.RPL_WHOISUSER: User whoUser = new User(tokens[3], tokens[4], tokens[5]); WhoisInfo whoisInfo = LookupInfo(whoUser.Nick); whoisInfo.user = whoUser; tokens[7] = RemoveLeadingColon(tokens[7]); whoisInfo.realName = CondenseStrings(tokens, 7); break; case ReplyCode.RPL_WHOISCHANNELS: WhoisInfo whoisChannelInfo = LookupInfo(tokens[3]); tokens[4] = RemoveLeadingColon(tokens[4]); int numberOfChannels = tokens.Length - 4; string[] channels = new String[numberOfChannels]; Array.Copy(tokens, 4, channels, 0, numberOfChannels); whoisChannelInfo.SetChannels(channels); break; case ReplyCode.RPL_WHOISSERVER: WhoisInfo whoisServerInfo = LookupInfo(tokens[3]); whoisServerInfo.ircServer = tokens[4]; tokens[5] = RemoveLeadingColon(tokens[5]); whoisServerInfo.serverDescription = CondenseStrings(tokens, 5); break; case ReplyCode.RPL_WHOISOPERATOR: WhoisInfo whoisOpInfo = LookupInfo(tokens[3]); whoisOpInfo.isOperator = true; break; case ReplyCode.RPL_WHOISIDLE: WhoisInfo whoisIdleInfo = LookupInfo(tokens[3]); whoisIdleInfo.idleTime = long.Parse(tokens[5], CultureInfo.InvariantCulture); break; case ReplyCode.RPL_ENDOFWHOIS: string nick = tokens[3]; WhoisInfo whoisEndInfo = LookupInfo(nick); OnWhois?.Invoke(whoisEndInfo); whoisInfos.Remove(nick); break; case ReplyCode.RPL_WHOWASUSER: User whoWasUser = new User(tokens[3], tokens[4], tokens[5]); tokens[7] = RemoveLeadingColon(tokens[7]); OnWhowas?.Invoke(whoWasUser, CondenseStrings(tokens, 7), false); break; case ReplyCode.RPL_ENDOFWHOWAS: OnWhowas?.Invoke(User.Empty, "", true); break; case ReplyCode.RPL_UMODEIS: { //First drop the '+' string chars = tokens[3].Substring(1); UserMode[] modes = Rfc2812Util.UserModesToArray(chars); OnUserModeRequest?.Invoke(modes); } break; case ReplyCode.RPL_CHANNELMODEIS: try { ChannelModeInfo[] modes = ChannelModeInfo.ParseModes(tokens, 4); OnChannelModeRequest?.Invoke(tokens[3], modes); } catch (Exception) { OnError.Fire(this, new ErrorMessageEventArgs(ReplyCode.UnparseableMessage, CondenseStrings(tokens, 0))); Debug.WriteLineIf(Rfc2812Util.IrcTrace.TraceWarning, "[" + Thread.CurrentThread.Name + "] Listener::ParseReply() Bad IRC MODE string=" + tokens[0]); } break; case ReplyCode.RPL_BANLIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Ban, tokens[4], Rfc2812Util.UserFromString(tokens[5]), Convert.ToInt64(tokens[6], CultureInfo.InvariantCulture), false); break; case ReplyCode.RPL_ENDOFBANLIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Ban, "", User.Empty, 0, true); break; case ReplyCode.RPL_INVITELIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Invitation, tokens[4], Rfc2812Util.UserFromString(tokens[5]), Convert.ToInt64(tokens[6]), false); break; case ReplyCode.RPL_ENDOFINVITELIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Invitation, "", User.Empty, 0, true); break; case ReplyCode.RPL_EXCEPTLIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Exception, tokens[4], Rfc2812Util.UserFromString(tokens[5]), Convert.ToInt64(tokens[6]), false); break; case ReplyCode.RPL_ENDOFEXCEPTLIST: OnChannelList?.Invoke(tokens[3], ChannelMode.Exception, "", User.Empty, 0, true); break; case ReplyCode.RPL_UNIQOPIS: OnChannelList?.Invoke(tokens[3], ChannelMode.ChannelCreator, tokens[4], User.Empty, 0, true); break; case ReplyCode.RPL_VERSION: OnVersion?.Invoke(CondenseStrings(tokens, 3)); break; case ReplyCode.RPL_TIME: OnTime?.Invoke(CondenseStrings(tokens, 3)); break; case ReplyCode.RPL_INFO: OnInfo?.Invoke(CondenseStrings(tokens, 3), false); break; case ReplyCode.RPL_ENDOFINFO: OnInfo?.Invoke(CondenseStrings(tokens, 3), true); break; case ReplyCode.RPL_ADMINME: case ReplyCode.RPL_ADMINLOC1: case ReplyCode.RPL_ADMINLOC2: case ReplyCode.RPL_ADMINEMAIL: OnAdmin?.Invoke(RemoveLeadingColon(CondenseStrings(tokens, 3))); break; case ReplyCode.RPL_LUSERCLIENT: case ReplyCode.RPL_LUSEROP: case ReplyCode.RPL_LUSERUNKNOWN: case ReplyCode.RPL_LUSERCHANNELS: case ReplyCode.RPL_LUSERME: OnLusers?.Invoke(RemoveLeadingColon(CondenseStrings(tokens, 3))); break; case ReplyCode.RPL_LINKS: OnLinks?.Invoke(tokens[3], //mask tokens[4], //hostname int.Parse(RemoveLeadingColon(tokens[5]), CultureInfo.InvariantCulture), //hopcount CondenseStrings(tokens, 6), false); break; case ReplyCode.RPL_ENDOFLINKS: OnLinks?.Invoke(String.Empty, String.Empty, -1, String.Empty, true); break; case ReplyCode.RPL_STATSLINKINFO: case ReplyCode.RPL_STATSCOMMANDS: case ReplyCode.RPL_STATSUPTIME: case ReplyCode.RPL_STATSOLINE: OnStats?.Invoke(GetQueryType(code), RemoveLeadingColon(CondenseStrings(tokens, 3)), false); break; case ReplyCode.RPL_ENDOFSTATS: OnStats?.Invoke(Rfc2812Util.CharToStatsQuery(tokens[3][0]), RemoveLeadingColon(CondenseStrings(tokens, 4)), true); break; default: HandleDefaultReply(code, tokens); break; } }