diff --git a/_discord_provider_8cs_source.html b/_discord_provider_8cs_source.html
index 783066c418..3337ee2a39 100644
--- a/_discord_provider_8cs_source.html
+++ b/_discord_provider_8cs_source.html
@@ -237,557 +237,557 @@ $(function() {
226 Optional<IMessageReference> replyToReference =
default;
-
-
- 229 replyToReference = discordMessage.MessageReference;
-
-
-
-
- 234 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
- 235 async Task SendToChannel(Snowflake channelId)
-
- 237 var result = await channelsClient.CreateMessageAsync(
-
-
-
- 241 messageReference: replyToReference,
- 242 ct: cancellationToken);
-
- 244 if (!result.IsSuccess)
-
- 246 "Failed to send to channel {0}: {1}",
-
-
-
-
-
-
-
-
- 255 var usersClient =
serviceProvider.GetRequiredService<IDiscordRestUserAPI>();
- 256 var currentGuildsResponse = await usersClient.GetCurrentUserGuildsAsync(ct: cancellationToken);
- 257 if (!currentGuildsResponse.IsSuccess)
-
-
- 260 "Error retrieving current discord guilds: {0}",
- 261 currentGuildsResponse.Error.Message);
-
-
-
- 265 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
-
- 267 var guildsChannelsTasks = currentGuildsResponse.Entity.Select(
- 268 guild => guildsClient.GetGuildChannelsAsync(guild.ID.Value, cancellationToken));
-
- 270 await Task.WhenAll(guildsChannelsTasks);
-
- 272 var unmappedTextChannels = guildsChannelsTasks
- 273 .Select(task => task.Result)
- 274 .SelectMany(guildChannels => guildChannels.Entity)
- 275 .Where(guildChannel => guildChannel.Type == ChannelType.GuildText);
+ 227 Optional<IAllowedMentions> allowedMentions =
default;
+
+
+ 230 replyToReference = discordMessage.MessageReference;
+ 231 allowedMentions =
new AllowedMentions(
+ 232 Parse:
new List<MentionType>
+
+ 234 MentionType.Everyone,
+
+
+
+ 238 MentionRepliedUser:
false);
+
+
+
+
+ 243 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
+ 244 async Task SendToChannel(Snowflake channelId)
+
+ 246 var result = await channelsClient.CreateMessageAsync(
+
+
+
+ 250 messageReference: replyToReference,
+ 251 allowedMentions: allowedMentions,
+ 252 ct: cancellationToken);
+
+ 254 if (!result.IsSuccess)
+
+ 256 "Failed to send to channel {0}: {1}",
+
+
+
+
+
+
+
+
+ 265 var usersClient =
serviceProvider.GetRequiredService<IDiscordRestUserAPI>();
+ 266 var currentGuildsResponse = await usersClient.GetCurrentUserGuildsAsync(ct: cancellationToken);
+ 267 if (!currentGuildsResponse.IsSuccess)
+
+
+ 270 "Error retrieving current discord guilds: {0}",
+ 271 currentGuildsResponse.Error.Message);
+
+
+
+ 275 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
-
- 278 unmappedTextChannels = unmappedTextChannels
-
-
+ 277 var guildsChannelsTasks = currentGuildsResponse.Entity.Select(
+ 278 guild => guildsClient.GetGuildChannelsAsync(guild.ID.Value, cancellationToken));
+
+ 280 await Task.WhenAll(guildsChannelsTasks);
-
- 283 if (unmappedTextChannels.Any())
-
- 285 Logger.LogTrace(
"Dispatching to {0} unmapped channels...", unmappedTextChannels.Count());
-
- 287 unmappedTextChannels.Select(
- 288 x => SendToChannel(x.ID)));
-
-
-
-
-
- 294 await SendToChannel(
new Snowflake(channelId));
-
-
-
- 298 if (e is OperationCanceledException)
- 299 cancellationToken.ThrowIfCancellationRequested();
- 300 Logger.LogWarning(e,
"Error sending discord message!");
-
-
+ 282 var unmappedTextChannels = guildsChannelsTasks
+ 283 .Select(task => task.Result)
+ 284 .SelectMany(guildChannels => guildChannels.Entity)
+ 285 .Where(guildChannel => guildChannel.Type == ChannelType.GuildText);
+
+
+ 288 unmappedTextChannels = unmappedTextChannels
+
+
+
+
+ 293 if (unmappedTextChannels.Any())
+
+ 295 Logger.LogTrace(
"Dispatching to {0} unmapped channels...", unmappedTextChannels.Count());
+
+ 297 unmappedTextChannels.Select(
+ 298 x => SendToChannel(x.ID)));
+
+
+
+
-
- 306 Models.RevisionInformation revisionInformation,
- 307 Version byondVersion,
- 308 DateTimeOffset? estimatedCompletionTime,
-
-
-
- 312 bool localCommitPushed,
- 313 CancellationToken cancellationToken)
-
- 315 localCommitPushed |= revisionInformation.CommitSha == revisionInformation.OriginCommitSha;
-
- 317 var fields =
BuildUpdateEmbedFields(revisionInformation, byondVersion, gitHubOwner, gitHubRepo, localCommitPushed);
-
-
- 320 Url =
"https://github.com/tgstation/tgstation-server",
- 321 IconUrl =
"https://avatars0.githubusercontent.com/u/1363778?s=280&v=4",
-
- 323 var embed =
new Embed
-
-
- 326 Colour = Color.FromArgb(0xF1, 0xC4, 0x0F),
- 327 Description =
"TGS has begun deploying active repository code to production.",
-
- 329 Title =
"Code Deployment",
- 330 Footer =
new EmbedFooter(
- 331 $
"In progress...{(estimatedCompletionTime.HasValue ? " ETA
" : String.Empty)}"),
- 332 Timestamp = estimatedCompletionTime ??
default,
-
-
- 335 Logger.LogTrace(
"Attempting to post deploy embed to channel {0}...", channelId);
- 336 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
-
- 338 var messageResponse = await channelsClient.CreateMessageAsync(
- 339 new Snowflake(channelId),
- 340 "DM: Deployment in Progress...",
- 341 embeds:
new List<IEmbed> { embed },
- 342 ct: cancellationToken)
-
+ 304 await SendToChannel(
new Snowflake(channelId));
+
+
+
+ 308 if (e is OperationCanceledException)
+ 309 cancellationToken.ThrowIfCancellationRequested();
+ 310 Logger.LogWarning(e,
"Error sending discord message!");
+
+
+
+
+ 316 Models.RevisionInformation revisionInformation,
+ 317 Version byondVersion,
+ 318 DateTimeOffset? estimatedCompletionTime,
+
+
+
+ 322 bool localCommitPushed,
+ 323 CancellationToken cancellationToken)
+
+ 325 localCommitPushed |= revisionInformation.CommitSha == revisionInformation.OriginCommitSha;
+
+ 327 var fields =
BuildUpdateEmbedFields(revisionInformation, byondVersion, gitHubOwner, gitHubRepo, localCommitPushed);
+
+
+ 330 Url =
"https://github.com/tgstation/tgstation-server",
+ 331 IconUrl =
"https://avatars0.githubusercontent.com/u/1363778?s=280&v=4",
+
+ 333 var embed =
new Embed
+
+
+ 336 Colour = Color.FromArgb(0xF1, 0xC4, 0x0F),
+ 337 Description =
"TGS has begun deploying active repository code to production.",
+
+ 339 Title =
"Code Deployment",
+ 340 Footer =
new EmbedFooter(
+ 341 $
"In progress...{(estimatedCompletionTime.HasValue ? " ETA
" : String.Empty)}"),
+ 342 Timestamp = estimatedCompletionTime ??
default,
+
- 345 if (!messageResponse.IsSuccess)
- 346 Logger.LogWarning(
"Failed to post deploy embed to channel {0}: {1}", channelId, messageResponse.Error.Message);
+ 345 Logger.LogTrace(
"Attempting to post deploy embed to channel {0}...", channelId);
+ 346 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
- 348 return async (errorMessage, dreamMakerOutput) =>
-
- 350 var completionString = errorMessage ==
null ?
"Succeeded" :
"Failed";
-
-
-
- 354 Author = embed.Author,
- 355 Colour = errorMessage ==
null ? Color.Green : Color.Red,
- 356 Description = errorMessage ==
null
- 357 ?
"The deployment completed successfully and will be available at the next server reboot."
- 358 :
"The deployment failed.",
-
-
- 361 Footer =
new EmbedFooter(
-
- 363 Timestamp = DateTimeOffset.UtcNow,
-
-
-
-
- 368 DiscordDMOutputDisplayType.Always =>
true,
- 369 DiscordDMOutputDisplayType.Never =>
false,
- 370 DiscordDMOutputDisplayType.OnError => errorMessage !=
null,
- 371 _ =>
throw new InvalidOperationException($
"Invalid DiscordDMOutputDisplayType: {outputDisplayType}"),
-
-
- 374 if (dreamMakerOutput !=
null)
-
-
- 377 const int MaxFieldValueLength = 1024;
- 378 showDMOutput = showDMOutput && dreamMakerOutput.Length < MaxFieldValueLength - (6 + Environment.NewLine.Length);
-
- 380 fields.Add(
new EmbedField(
-
- 382 $
"```{Environment.NewLine}{dreamMakerOutput}{Environment.NewLine}```",
-
-
-
- 386 if (errorMessage !=
null)
- 387 fields.Add(
new EmbedField(
-
-
-
-
- 392 var updatedMessage = $
"DM: Deployment {completionString}!";
-
- 394 async Task CreateUpdatedMessage()
-
- 396 var createUpdatedMessageResponse = await channelsClient.CreateMessageAsync(
- 397 new Snowflake(channelId),
-
- 399 embeds:
new List<IEmbed> { embed },
- 400 ct: cancellationToken)
-
-
- 403 if (!createUpdatedMessageResponse.IsSuccess)
-
- 405 "Creating updated deploy embed failed! Error: {0}",
- 406 createUpdatedMessageResponse.Error.Message);
-
-
- 409 if (!messageResponse.IsSuccess)
- 410 await CreateUpdatedMessage();
-
-
- 413 var editResponse = await channelsClient.EditMessageAsync(
- 414 new Snowflake(channelId),
- 415 messageResponse.Entity.ID,
-
- 417 embeds:
new List<IEmbed> { embed },
- 418 ct: cancellationToken)
-
-
- 421 if (!editResponse.IsSuccess)
-
-
- 424 "Updating deploy embed {0} failed, attempting new post! Error: {1}",
- 425 messageResponse.Entity.ID,
- 426 editResponse.Error.Message);
- 427 await CreateUpdatedMessage();
-
-
-
-
-
- 434 public async Task<Result>
RespondAsync(IMessageCreate messageCreateEvent, CancellationToken cancellationToken)
-
- 436 if (messageCreateEvent ==
null)
- 437 throw new ArgumentNullException(nameof(messageCreateEvent));
-
- 439 if ((messageCreateEvent.Type != MessageType.Default
- 440 && messageCreateEvent.Type != MessageType.InlineReply)
-
- 442 return Result.FromSuccess();
-
- 444 var messageReference =
new MessageReference
-
- 446 ChannelID = messageCreateEvent.ChannelID,
- 447 GuildID = messageCreateEvent.GuildID,
- 448 MessageID = messageCreateEvent.ID,
- 449 FailIfNotExists =
false,
-
-
- 452 if (
basedMeme && messageCreateEvent.Content.Equals(
"Based on what?", StringComparison.OrdinalIgnoreCase))
-
-
-
-
-
- 458 MessageReference = messageReference,
-
-
-
- 462 Text =
"https://youtu.be/LrNu-SuFF_o",
-
- 464 messageCreateEvent.ChannelID.Value,
-
- 466 return Result.FromSuccess();
-
-
- 469 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
- 470 var channelResponse = await channelsClient.GetChannelAsync(messageCreateEvent.ChannelID, cancellationToken);
- 471 if (!channelResponse.IsSuccess)
-
-
- 474 "Failed to get channel {0} in response to message {1}!",
- 475 messageCreateEvent.ChannelID,
- 476 messageCreateEvent.ID);
-
-
- 479 return Result.FromSuccess();
-
-
- 482 var pm = channelResponse.Entity.Type == ChannelType.DM || channelResponse.Entity.Type == ChannelType.GroupDM;
- 483 var shouldNotAnswer = !pm;
-
-
-
+ 348 var messageResponse = await channelsClient.CreateMessageAsync(
+ 349 new Snowflake(channelId),
+ 350 "DM: Deployment in Progress...",
+ 351 embeds:
new List<IEmbed> { embed },
+ 352 ct: cancellationToken)
+
+
+ 355 if (!messageResponse.IsSuccess)
+ 356 Logger.LogWarning(
"Failed to post deploy embed to channel {0}: {1}", channelId, messageResponse.Error.Message);
+
+ 358 return async (errorMessage, dreamMakerOutput) =>
+
+ 360 var completionString = errorMessage ==
null ?
"Succeeded" :
"Failed";
+
+
+
+ 364 Author = embed.Author,
+ 365 Colour = errorMessage ==
null ? Color.Green : Color.Red,
+ 366 Description = errorMessage ==
null
+ 367 ?
"The deployment completed successfully and will be available at the next server reboot."
+ 368 :
"The deployment failed.",
+
+
+ 371 Footer =
new EmbedFooter(
+
+ 373 Timestamp = DateTimeOffset.UtcNow,
+
+
+
+
+ 378 DiscordDMOutputDisplayType.Always =>
true,
+ 379 DiscordDMOutputDisplayType.Never =>
false,
+ 380 DiscordDMOutputDisplayType.OnError => errorMessage !=
null,
+ 381 _ =>
throw new InvalidOperationException($
"Invalid DiscordDMOutputDisplayType: {outputDisplayType}"),
+
+
+ 384 if (dreamMakerOutput !=
null)
+
+
+ 387 const int MaxFieldValueLength = 1024;
+ 388 showDMOutput = showDMOutput && dreamMakerOutput.Length < MaxFieldValueLength - (6 + Environment.NewLine.Length);
+
+ 390 fields.Add(
new EmbedField(
+
+ 392 $
"```{Environment.NewLine}{dreamMakerOutput}{Environment.NewLine}```",
+
+
+
+ 396 if (errorMessage !=
null)
+ 397 fields.Add(
new EmbedField(
+
+
+
+
+ 402 var updatedMessage = $
"DM: Deployment {completionString}!";
+
+ 404 async Task CreateUpdatedMessage()
+
+ 406 var createUpdatedMessageResponse = await channelsClient.CreateMessageAsync(
+ 407 new Snowflake(channelId),
+
+ 409 embeds:
new List<IEmbed> { embed },
+ 410 ct: cancellationToken)
+
+
+ 413 if (!createUpdatedMessageResponse.IsSuccess)
+
+ 415 "Creating updated deploy embed failed! Error: {0}",
+ 416 createUpdatedMessageResponse.Error.Message);
+
+
+ 419 if (!messageResponse.IsSuccess)
+ 420 await CreateUpdatedMessage();
+
+
+ 423 var editResponse = await channelsClient.EditMessageAsync(
+ 424 new Snowflake(channelId),
+ 425 messageResponse.Entity.ID,
+
+ 427 embeds:
new List<IEmbed> { embed },
+ 428 ct: cancellationToken)
+
+
+ 431 if (!editResponse.IsSuccess)
+
+
+ 434 "Updating deploy embed {0} failed, attempting new post! Error: {1}",
+ 435 messageResponse.Entity.ID,
+ 436 editResponse.Error.Message);
+ 437 await CreateUpdatedMessage();
+
+
+
+
+
+ 444 public async Task<Result>
RespondAsync(IMessageCreate messageCreateEvent, CancellationToken cancellationToken)
+
+ 446 if (messageCreateEvent ==
null)
+ 447 throw new ArgumentNullException(nameof(messageCreateEvent));
+
+ 449 if ((messageCreateEvent.Type != MessageType.Default
+ 450 && messageCreateEvent.Type != MessageType.InlineReply)
+
+ 452 return Result.FromSuccess();
+
+ 454 var messageReference =
new MessageReference
+
+ 456 ChannelID = messageCreateEvent.ChannelID,
+ 457 GuildID = messageCreateEvent.GuildID,
+ 458 MessageID = messageCreateEvent.ID,
+ 459 FailIfNotExists =
false,
+
+
+ 462 if (
basedMeme && messageCreateEvent.Content.Equals(
"Based on what?", StringComparison.OrdinalIgnoreCase))
+
+
+
+
+
+ 468 MessageReference = messageReference,
+
+
+
+ 472 Text =
"https://youtu.be/LrNu-SuFF_o",
+
+ 474 messageCreateEvent.ChannelID.Value,
+
+ 476 return Result.FromSuccess();
+
+
+ 479 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
+ 480 var channelResponse = await channelsClient.GetChannelAsync(messageCreateEvent.ChannelID, cancellationToken);
+ 481 if (!channelResponse.IsSuccess)
+
+
+ 484 "Failed to get channel {0} in response to message {1}!",
+ 485 messageCreateEvent.ChannelID,
+ 486 messageCreateEvent.ID);
-
- 489 var mentionedUs = messageCreateEvent.Mentions.Any(x => x.ID ==
currentUserId)
- 490 || (!shouldNotAnswer && content.Split(
' ').First().Equals(
ChatManager.
CommonMention, StringComparison.OrdinalIgnoreCase));
+
+ 489 return Result.FromSuccess();
+
-
-
-
-
- 496 "Ignoring mention from {0} ({1}) by {2} ({3}). Channel not mapped!",
- 497 messageCreateEvent.ChannelID,
- 498 channelResponse.Entity.Name,
- 499 messageCreateEvent.Author.ID,
- 500 messageCreateEvent.Author.Username);
+ 492 var pm = channelResponse.Entity.Type == ChannelType.DM || channelResponse.Entity.Type == ChannelType.GroupDM;
+ 493 var shouldNotAnswer = !pm;
+
+
+
+
+
+ 499 var mentionedUs = messageCreateEvent.Mentions.Any(x => x.ID ==
currentUserId)
+ 500 || (!shouldNotAnswer && content.Split(
' ').First().Equals(
ChatManager.
CommonMention, StringComparison.OrdinalIgnoreCase));
- 502 return Result.FromSuccess();
-
-
- 505 string guildName =
"UNKNOWN";
-
-
- 508 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
- 509 var messageGuildResponse = await guildsClient.GetGuildAsync(messageCreateEvent.GuildID.Value,
false, cancellationToken);
- 510 if (messageGuildResponse.IsSuccess)
- 511 guildName = messageGuildResponse.Entity.Name;
-
-
- 514 "Failed to get channel {0} in response to message {1}!",
- 515 messageCreateEvent.ChannelID,
- 516 messageCreateEvent.ID);
-
-
-
-
- 521 MessageReference = messageReference,
-
-
-
- 525 RealId = messageCreateEvent.Author.ID.Value,
-
-
- 528 RealId = messageCreateEvent.ChannelID.Value,
- 529 IsPrivateChannel = pm,
- 530 ConnectionName = pm ? messageCreateEvent.Author.Username : guildName,
- 531 FriendlyName = channelResponse.Entity.Name.Value,
- 532 EmbedsSupported =
true,
-
-
-
- 536 FriendlyName = messageCreateEvent.Author.Username,
-
-
-
-
-
- 542 return Result.FromSuccess();
-
-
- 546 public Task<Result>
RespondAsync(IReady readyEvent, CancellationToken cancellationToken)
-
- 548 if (readyEvent ==
null)
- 549 throw new ArgumentNullException(nameof(readyEvent));
+
+
+
+
+ 506 "Ignoring mention from {0} ({1}) by {2} ({3}). Channel not mapped!",
+ 507 messageCreateEvent.ChannelID,
+ 508 channelResponse.Entity.Name,
+ 509 messageCreateEvent.Author.ID,
+ 510 messageCreateEvent.Author.Username);
+
+ 512 return Result.FromSuccess();
+
+
+ 515 string guildName =
"UNKNOWN";
+
+
+ 518 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
+ 519 var messageGuildResponse = await guildsClient.GetGuildAsync(messageCreateEvent.GuildID.Value,
false, cancellationToken);
+ 520 if (messageGuildResponse.IsSuccess)
+ 521 guildName = messageGuildResponse.Entity.Name;
+
+
+ 524 "Failed to get channel {0} in response to message {1}!",
+ 525 messageCreateEvent.ChannelID,
+ 526 messageCreateEvent.ID);
+
+
+
+
+ 531 MessageReference = messageReference,
+
+
+
+ 535 RealId = messageCreateEvent.Author.ID.Value,
+
+
+ 538 RealId = messageCreateEvent.ChannelID.Value,
+ 539 IsPrivateChannel = pm,
+ 540 ConnectionName = pm ? messageCreateEvent.Author.Username : guildName,
+ 541 FriendlyName = channelResponse.Entity.Name.Value,
+ 542 EmbedsSupported =
true,
+
+
+
+ 546 FriendlyName = messageCreateEvent.Author.Username,
+
+
+
- 551 Logger.LogTrace(
"Gatway ready. Version: {version}", readyEvent.Version);
-
- 553 return Task.FromResult(Result.FromSuccess());
-
-
- 557 protected override async Task
Connect(CancellationToken cancellationToken)
-
-
-
-
-
-
- 564 throw new InvalidOperationException(
"Discord gateway still active!");
+
+ 552 return Result.FromSuccess();
+
+
+ 556 public Task<Result>
RespondAsync(IReady readyEvent, CancellationToken cancellationToken)
+
+ 558 if (readyEvent ==
null)
+ 559 throw new ArgumentNullException(nameof(readyEvent));
+
+ 561 Logger.LogTrace(
"Gatway ready. Version: {version}", readyEvent.Version);
+
+ 563 return Task.FromResult(Result.FromSuccess());
+
-
-
-
- 569 var gatewayCancellationToken =
gatewayCts.Token;
- 570 var gatewayClient =
serviceProvider.GetRequiredService<DiscordGatewayClient>();
-
- 572 Task<Result> localGatewayTask;
-
-
- 575 using var gatewayConnectionAbortRegistration = cancellationToken.Register(() =>
gatewayReadyTcs.TrySetCanceled());
- 576 gatewayCancellationToken.Register(() =>
Logger.LogTrace(
"Stopping gateway client..."));
-
-
- 579 localGatewayTask = gatewayClient.RunAsync(gatewayCancellationToken);
-
-
-
-
- 584 if (localGatewayTask.IsCompleted || cancellationToken.IsCancellationRequested)
-
-
- 587 var userClient =
serviceProvider.GetRequiredService<IDiscordRestUserAPI>();
-
- 589 using var localCombinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, gatewayCancellationToken);
- 590 var currentUserResult = await userClient.GetCurrentUserAsync(localCombinedCts.Token);
- 591 if (!currentUserResult.IsSuccess)
-
- 593 Logger.LogWarning(
"Unable to retrieve current user: {0}", currentUserResult.Error.Message);
-
-
+ 567 protected override async Task
Connect(CancellationToken cancellationToken)
+
+
+
+
+
+
+ 574 throw new InvalidOperationException(
"Discord gateway still active!");
+
+
+
+
+ 579 var gatewayCancellationToken =
gatewayCts.Token;
+ 580 var gatewayClient =
serviceProvider.GetRequiredService<DiscordGatewayClient>();
+
+ 582 Task<Result> localGatewayTask;
+
+
+ 585 using var gatewayConnectionAbortRegistration = cancellationToken.Register(() =>
gatewayReadyTcs.TrySetCanceled());
+ 586 gatewayCancellationToken.Register(() =>
Logger.LogTrace(
"Stopping gateway client..."));
+
+
+ 589 localGatewayTask = gatewayClient.RunAsync(gatewayCancellationToken);
+
+
+
+
+ 594 if (localGatewayTask.IsCompleted || cancellationToken.IsCancellationRequested)
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 615 protected override async Task
DisconnectImpl(CancellationToken cancellationToken)
-
- 617 Task<Result> localGatewayTask;
- 618 CancellationTokenSource localGatewayCts;
-
-
-
-
-
-
- 625 if (localGatewayTask ==
null)
-
-
-
- 629 localGatewayCts.Cancel();
- 630 var gatewayResult = await localGatewayTask;
- 631 if (!gatewayResult.IsSuccess)
- 632 Logger.LogWarning(
"Gateway issue: {0}", gatewayResult.Error.Message);
-
- 634 localGatewayCts.Dispose();
-
-
- 638 protected override async Task<IReadOnlyCollection<Tuple<Models.ChatChannel,
ChannelRepresentation>>>
MapChannelsImpl(IEnumerable<Models.ChatChannel> channels, CancellationToken cancellationToken)
-
- 640 if (channels ==
null)
- 641 throw new ArgumentNullException(nameof(channels));
-
- 643 var remapRequired =
false;
-
- 645 async Task<Tuple<Models.ChatChannel,
ChannelRepresentation>> GetModelChannelFromDBChannel(Models.ChatChannel channelFromDB)
-
- 647 if (!channelFromDB.DiscordChannelId.HasValue)
- 648 throw new InvalidOperationException(
"ChatChannel missing DiscordChannelId!");
-
- 650 var channelId = channelFromDB.DiscordChannelId.Value;
- 651 string connectionName;
-
-
-
-
- 656 friendlyName =
"(Unmapped accessible channels)";
-
-
-
- 660 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
- 661 var discordChannelResponse = await channelsClient.GetChannelAsync(
new Snowflake(channelId), cancellationToken);
- 662 if (!discordChannelResponse.IsSuccess)
-
-
- 665 "Error retrieving discord channel {channelId}: {error} Inner: {innerError}",
-
- 667 discordChannelResponse.Error.Message,
- 668 discordChannelResponse.Inner?.Error?.Message);
- 669 remapRequired =
true;
-
-
-
- 673 var channelType = discordChannelResponse.Entity.Type;
- 674 if (channelType != ChannelType.GuildText && channelType != ChannelType.GuildAnnouncement)
-
- 676 Logger.LogWarning(
"Cound not map channel {channelId}! Incorrect type: {channelType}", channelId, discordChannelResponse.Entity.Type);
-
-
-
- 680 friendlyName = discordChannelResponse.Entity.Name.Value;
- 681 var guildId = discordChannelResponse.Entity.GuildID.Value;
+ 597 var userClient =
serviceProvider.GetRequiredService<IDiscordRestUserAPI>();
+
+ 599 using var localCombinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, gatewayCancellationToken);
+ 600 var currentUserResult = await userClient.GetCurrentUserAsync(localCombinedCts.Token);
+ 601 if (!currentUserResult.IsSuccess)
+
+ 603 Logger.LogWarning(
"Unable to retrieve current user: {0}", currentUserResult.Error.Message);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 625 protected override async Task
DisconnectImpl(CancellationToken cancellationToken)
+
+ 627 Task<Result> localGatewayTask;
+ 628 CancellationTokenSource localGatewayCts;
+
+
+
+
+
+
+ 635 if (localGatewayTask ==
null)
+
+
+
+ 639 localGatewayCts.Cancel();
+ 640 var gatewayResult = await localGatewayTask;
+ 641 if (!gatewayResult.IsSuccess)
+ 642 Logger.LogWarning(
"Gateway issue: {0}", gatewayResult.Error.Message);
+
+ 644 localGatewayCts.Dispose();
+
+
+ 648 protected override async Task<IReadOnlyCollection<Tuple<Models.ChatChannel,
ChannelRepresentation>>>
MapChannelsImpl(IEnumerable<Models.ChatChannel> channels, CancellationToken cancellationToken)
+
+ 650 if (channels ==
null)
+ 651 throw new ArgumentNullException(nameof(channels));
+
+ 653 var remapRequired =
false;
+
+ 655 async Task<Tuple<Models.ChatChannel,
ChannelRepresentation>> GetModelChannelFromDBChannel(Models.ChatChannel channelFromDB)
+
+ 657 if (!channelFromDB.DiscordChannelId.HasValue)
+ 658 throw new InvalidOperationException(
"ChatChannel missing DiscordChannelId!");
+
+ 660 var channelId = channelFromDB.DiscordChannelId.Value;
+ 661 string connectionName;
+
+
+
+
+ 666 friendlyName =
"(Unmapped accessible channels)";
+
+
+
+ 670 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
+ 671 var discordChannelResponse = await channelsClient.GetChannelAsync(
new Snowflake(channelId), cancellationToken);
+ 672 if (!discordChannelResponse.IsSuccess)
+
+
+ 675 "Error retrieving discord channel {channelId}: {error} Inner: {innerError}",
+
+ 677 discordChannelResponse.Error.Message,
+ 678 discordChannelResponse.Inner?.Error?.Message);
+ 679 remapRequired =
true;
+
+
- 683 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
- 684 var guildsResponse = await guildsClient.GetGuildAsync(
-
-
-
- 688 if (!guildsResponse.IsSuccess)
-
-
- 691 "Error retrieving discord guild {guildID}: {error} Inner: {innerError}",
-
- 693 guildsResponse.Error.Message,
- 694 guildsResponse.Inner?.Error?.Message);
- 695 remapRequired =
true;
-
-
-
- 699 connectionName = guildsResponse.Entity.Name;
-
-
-
-
-
- 705 IsAdminChannel = channelFromDB.IsAdminChannel ==
true,
- 706 ConnectionName = connectionName,
- 707 FriendlyName = friendlyName,
- 708 IsPrivateChannel =
false,
- 709 Tag = channelFromDB.
Tag,
- 710 EmbedsSupported =
true,
-
-
- 713 Logger.LogTrace(
"Mapped channel {0}: {1}", channelModel.RealId, channelModel.FriendlyName);
- 714 return Tuple.Create(channelFromDB, channelModel);
-
-
-
- 718 .Select(x => GetModelChannelFromDBChannel(x))
-
-
- 721 await Task.WhenAll(tasks);
+ 683 var channelType = discordChannelResponse.Entity.Type;
+ 684 if (channelType != ChannelType.GuildText && channelType != ChannelType.GuildAnnouncement)
+
+ 686 Logger.LogWarning(
"Cound not map channel {channelId}! Incorrect type: {channelType}", channelId, discordChannelResponse.Entity.Type);
+
+
+
+ 690 friendlyName = discordChannelResponse.Entity.Name.Value;
+ 691 var guildId = discordChannelResponse.Entity.GuildID.Value;
+
+ 693 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
+ 694 var guildsResponse = await guildsClient.GetGuildAsync(
+
+
+
+ 698 if (!guildsResponse.IsSuccess)
+
+
+ 701 "Error retrieving discord guild {guildID}: {error} Inner: {innerError}",
+
+ 703 guildsResponse.Error.Message,
+ 704 guildsResponse.Inner?.Error?.Message);
+ 705 remapRequired =
true;
+
+
+
+ 709 connectionName = guildsResponse.Entity.Name;
+
+
+
+
+
+ 715 IsAdminChannel = channelFromDB.IsAdminChannel ==
true,
+ 716 ConnectionName = connectionName,
+ 717 FriendlyName = friendlyName,
+ 718 IsPrivateChannel =
false,
+ 719 Tag = channelFromDB.
Tag,
+ 720 EmbedsSupported =
true,
+
- 723 var enumerator = tasks
- 724 .Select(x => x.Result)
- 725 .Where(x => x !=
null)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 745 #pragma warning disable CA1502
-
-
-
-
-
- 751 List<string> embedErrors =
new List<string>();
- 752 Optional<Color> colour =
default;
-
- 754 if (Int32.TryParse(embed.
Colour.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var argb))
- 755 colour = Color.FromArgb(argb);
-
-
-
- 759 CultureInfo.InvariantCulture,
- 760 "Invalid embed colour: {0}",
-
-
-
-
- 765 embedErrors.Add(
"Null or whitespace embed author name!");
-
-
-
- 769 List<IEmbedField> fields =
null;
-
-
- 772 fields =
new List<IEmbedField>();
-
- 774 foreach (var field
in embed.
Fields)
-
-
-
- 778 if (String.IsNullOrWhiteSpace(field.Name))
-
-
-
- 782 CultureInfo.InvariantCulture,
- 783 "Null or whitespace field author at index {0}!",
-
-
-
-
- 788 if (String.IsNullOrWhiteSpace(field.Value))
+ 723 Logger.LogTrace(
"Mapped channel {0}: {1}", channelModel.RealId, channelModel.FriendlyName);
+ 724 return Tuple.Create(channelFromDB, channelModel);
+
+
+
+ 728 .Select(x => GetModelChannelFromDBChannel(x))
+
+
+ 731 await Task.WhenAll(tasks);
+
+ 733 var enumerator = tasks
+ 734 .Select(x => x.Result)
+ 735 .Where(x => x !=
null)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 755 #pragma warning disable CA1502
+
+
+
+
+
+ 761 List<string> embedErrors =
new List<string>();
+ 762 Optional<Color> colour =
default;
+
+ 764 if (Int32.TryParse(embed.
Colour.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var argb))
+ 765 colour = Color.FromArgb(argb);
+
+
+
+ 769 CultureInfo.InvariantCulture,
+ 770 "Invalid embed colour: {0}",
+
+
+
+
+ 775 embedErrors.Add(
"Null or whitespace embed author name!");
+
+
+
+ 779 List<IEmbedField> fields =
null;
+
+
+ 782 fields =
new List<IEmbedField>();
+
+ 784 foreach (var field
in embed.
Fields)
+
+
+
+ 788 if (String.IsNullOrWhiteSpace(field.Name))
@@ -797,124 +797,134 @@ $(function() {
-
-
-
- 801 fields.Add(
new EmbedField(field.Name, field.Value)
-
- 803 IsInline = field.IsInline ?? default(Optional<bool>),
-
-
-
+ 798 if (String.IsNullOrWhiteSpace(field.Value))
+
+
+
+ 802 CultureInfo.InvariantCulture,
+ 803 "Null or whitespace field author at index {0}!",
+
+
+
-
-
- 810 embedErrors.Add(
"Null or whitespace embed footer text!");
-
-
-
- 814 if (embed.
Image !=
null && String.IsNullOrWhiteSpace(embed.
Image.
Url))
-
- 816 embedErrors.Add(
"Null or whitespace embed image url!");
-
-
-
-
-
- 822 embedErrors.Add(
"Null or whitespace embed thumbnail url!");
- 823 embed.Thumbnail =
null;
-
-
- 826 Optional<DateTimeOffset> timestampOptional =
default;
-
- 828 if (DateTimeOffset.TryParse(embed.
Timestamp, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var timestamp))
- 829 timestampOptional = timestamp.ToUniversalTime();
-
-
-
- 833 CultureInfo.InvariantCulture,
- 834 "Invalid embed timestamp: {0}",
-
-
- 837 var discordEmbed =
new Embed
-
- 839 Author = embed.Author !=
null
-
-
- 842 IconUrl = embed.Author.IconUrl ??
default(Optional<string>),
- 843 ProxyIconUrl = embed.Author.ProxyIconUrl ??
default(Optional<string>),
- 844 Url = embed.Author.Url ??
default(Optional<string>),
-
- 846 :
default(Optional<IEmbedAuthor>),
-
- 848 Description = embed.Description ??
default(Optional<string>),
- 849 Fields = fields ??
default(Optional<IReadOnlyList<IEmbedField>>),
- 850 Footer = embed.Footer !=
null
-
-
- 853 IconUrl = embed.Footer.IconUrl ??
default(Optional<string>),
- 854 ProxyIconUrl = embed.Footer.ProxyIconUrl ??
default(Optional<string>),
+
+
+
+ 811 fields.Add(
new EmbedField(field.Name, field.Value)
+
+ 813 IsInline = field.IsInline ?? default(Optional<bool>),
+
+
+
+
+
+
+ 820 embedErrors.Add(
"Null or whitespace embed footer text!");
+
+
+
+ 824 if (embed.
Image !=
null && String.IsNullOrWhiteSpace(embed.
Image.
Url))
+
+ 826 embedErrors.Add(
"Null or whitespace embed image url!");
+
+
+
+
+
+ 832 embedErrors.Add(
"Null or whitespace embed thumbnail url!");
+ 833 embed.Thumbnail =
null;
+
+
+ 836 Optional<DateTimeOffset> timestampOptional =
default;
+
+ 838 if (DateTimeOffset.TryParse(embed.
Timestamp, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var timestamp))
+ 839 timestampOptional = timestamp.ToUniversalTime();
+
+
+
+ 843 CultureInfo.InvariantCulture,
+ 844 "Invalid embed timestamp: {0}",
+
+
+ 847 var discordEmbed =
new Embed
+
+ 849 Author = embed.Author !=
null
+
+
+ 852 IconUrl = embed.Author.IconUrl ??
default(Optional<string>),
+ 853 ProxyIconUrl = embed.Author.ProxyIconUrl ??
default(Optional<string>),
+ 854 Url = embed.Author.Url ??
default(Optional<string>),
-
- 857 Image = embed.Image !=
null
-
-
- 860 Width = embed.Image.Width ??
default(Optional<int>),
- 861 Height = embed.Image.Height ??
default(Optional<int>),
- 862 ProxyUrl = embed.Image.ProxyUrl ??
default(Optional<string>),
-
- 864 :
default(Optional<IEmbedImage>),
-
-
-
- 868 Name = embed.Provider.Name ??
default(Optional<string>),
- 869 Url = embed.Provider.Url ??
default(Optional<string>),
-
- 871 :
default(Optional<IEmbedProvider>),
- 872 Thumbnail = embed.Thumbnail !=
null
-
-
- 875 Width = embed.Thumbnail.Width ??
default(Optional<int>),
- 876 Height = embed.Thumbnail.Height ??
default(Optional<int>),
- 877 ProxyUrl = embed.Thumbnail.ProxyUrl ??
default(Optional<string>),
-
- 879 :
default(Optional<IEmbedThumbnail>),
- 880 Timestamp = timestampOptional,
- 881 Title = embed.Title ??
default(Optional<string>),
- 882 Url = embed.Url ??
default(Optional<string>),
- 883 Video = embed.Video !=
null
-
-
- 886 Url = embed.Video.Url ??
default(Optional<string>),
- 887 Width = embed.Video.Width ??
default(Optional<int>),
- 888 Height = embed.Video.Height ??
default(Optional<int>),
- 889 ProxyUrl = embed.Video.ProxyUrl ??
default(Optional<string>),
-
- 891 :
default(Optional<IEmbedVideo>),
-
-
- 894 var result =
new List<IEmbed> { discordEmbed };
-
- 896 if (embedErrors.Count > 0)
-
- 898 var joinedErrors = String.Join(Environment.NewLine, embedErrors);
- 899 Logger.LogError(
"Embed description contains errors:{newLine}{issues}", Environment.NewLine, joinedErrors);
-
-
- 902 Title =
"TGS Embed Errors",
- 903 Description = joinedErrors,
-
- 905 Footer =
new EmbedFooter(
"Please report this to your codebase's maintainers."),
- 906 Timestamp = DateTimeOffset.UtcNow,
-
-
-
-
-
- 912 #pragma warning restore CA1502
-
- 914#pragma warning restore CA1506
-
+ 856 :
default(Optional<IEmbedAuthor>),
+
+ 858 Description = embed.Description ??
default(Optional<string>),
+ 859 Fields = fields ??
default(Optional<IReadOnlyList<IEmbedField>>),
+ 860 Footer = embed.Footer !=
null
+
+
+ 863 IconUrl = embed.Footer.IconUrl ??
default(Optional<string>),
+ 864 ProxyIconUrl = embed.Footer.ProxyIconUrl ??
default(Optional<string>),
+
+
+ 867 Image = embed.Image !=
null
+
+
+ 870 Width = embed.Image.Width ??
default(Optional<int>),
+ 871 Height = embed.Image.Height ??
default(Optional<int>),
+ 872 ProxyUrl = embed.Image.ProxyUrl ??
default(Optional<string>),
+
+ 874 :
default(Optional<IEmbedImage>),
+
+
+
+ 878 Name = embed.Provider.Name ??
default(Optional<string>),
+ 879 Url = embed.Provider.Url ??
default(Optional<string>),
+
+ 881 :
default(Optional<IEmbedProvider>),
+ 882 Thumbnail = embed.Thumbnail !=
null
+
+
+ 885 Width = embed.Thumbnail.Width ??
default(Optional<int>),
+ 886 Height = embed.Thumbnail.Height ??
default(Optional<int>),
+ 887 ProxyUrl = embed.Thumbnail.ProxyUrl ??
default(Optional<string>),
+
+ 889 :
default(Optional<IEmbedThumbnail>),
+ 890 Timestamp = timestampOptional,
+ 891 Title = embed.Title ??
default(Optional<string>),
+ 892 Url = embed.Url ??
default(Optional<string>),
+ 893 Video = embed.Video !=
null
+
+
+ 896 Url = embed.Video.Url ??
default(Optional<string>),
+ 897 Width = embed.Video.Width ??
default(Optional<int>),
+ 898 Height = embed.Video.Height ??
default(Optional<int>),
+ 899 ProxyUrl = embed.Video.ProxyUrl ??
default(Optional<string>),
+
+ 901 :
default(Optional<IEmbedVideo>),
+
+
+ 904 var result =
new List<IEmbed> { discordEmbed };
+
+ 906 if (embedErrors.Count > 0)
+
+ 908 var joinedErrors = String.Join(Environment.NewLine, embedErrors);
+ 909 Logger.LogError(
"Embed description contains errors:{newLine}{issues}", Environment.NewLine, joinedErrors);
+
+
+ 912 Title =
"TGS Embed Errors",
+ 913 Description = joinedErrors,
+
+ 915 Footer =
new EmbedFooter(
"Please report this to your codebase's maintainers."),
+ 916 Timestamp = DateTimeOffset.UtcNow,
+
+
+
+
+
+ 922 #pragma warning restore CA1502
+
+ 924#pragma warning restore CA1506
+
ChatConnectionStringBuilder for ChatProvider.Discord.
string? ConnectionString
The information used to connect to the Provider.
Represents a Providers.IProvider channel.
@@ -935,20 +945,20 @@ $(function() {
Task< Result > gatewayTask
The Task representing the lifetime of the client.
Snowflake currentUserId
The bot's Snowflake.
static string NormalizeMentions(string fromDiscord)
Normalize a discord mention string.
-override async Task< IReadOnlyCollection< Tuple< Models.ChatChannel, ChannelRepresentation > > > MapChannelsImpl(IEnumerable< Models.ChatChannel > channels, CancellationToken cancellationToken)
+override async Task< IReadOnlyCollection< Tuple< Models.ChatChannel, ChannelRepresentation > > > MapChannelsImpl(IEnumerable< Models.ChatChannel > channels, CancellationToken cancellationToken)
CancellationTokenSource gatewayCts
The CancellationTokenSource for the gatewayTask.
readonly IAssemblyInformationProvider assemblyInformationProvider
The IAssemblyInformationProvider for the DiscordProvider.
-async Task< Result > RespondAsync(IMessageCreate messageCreateEvent, CancellationToken cancellationToken)
+async Task< Result > RespondAsync(IMessageCreate messageCreateEvent, CancellationToken cancellationToken)
readonly DiscordDMOutputDisplayType outputDisplayType
The DiscordDMOutputDisplayType.
static List< IEmbedField > BuildUpdateEmbedFields(Models.RevisionInformation revisionInformation, Version byondVersion, string gitHubOwner, string gitHubRepo, bool localCommitPushed)
Create a List<T> of IEmbedFields for a discord update embed.
-override async Task Connect(CancellationToken cancellationToken)
Attempt to connect the Provider. A Task representing the running operation.
-override async Task< Func< string, string, Task > > SendUpdateMessage(Models.RevisionInformation revisionInformation, Version byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, ulong channelId, bool localCommitPushed, CancellationToken cancellationToken)
+override async Task Connect(CancellationToken cancellationToken)
Attempt to connect the Provider. A Task representing the running operation.
+override async Task< Func< string, string, Task > > SendUpdateMessage(Models.RevisionInformation revisionInformation, Version byondVersion, DateTimeOffset? estimatedCompletionTime, string gitHubOwner, string gitHubRepo, ulong channelId, bool localCommitPushed, CancellationToken cancellationToken)
override async ValueTask DisposeAsync()
override bool Connected
If the IProvider is currently connected.
-Optional< IReadOnlyList< IEmbed > > ConvertEmbed(ChatEmbed embed)
Convert a ChatEmbed to an IEmbed parameters.
+Optional< IReadOnlyList< IEmbed > > ConvertEmbed(ChatEmbed embed)
Convert a ChatEmbed to an IEmbed parameters.
TaskCompletionSource< object > gatewayReadyTcs
The TaskCompletionSource<TResult> for the initial gateway connection event.
-Task< Result > RespondAsync(IReady readyEvent, CancellationToken cancellationToken)
-override async Task DisconnectImpl(CancellationToken cancellationToken)
Gracefully disconnects the provider. A Task representing the running operation.
+Task< Result > RespondAsync(IReady readyEvent, CancellationToken cancellationToken)
+override async Task DisconnectImpl(CancellationToken cancellationToken)
Gracefully disconnects the provider. A Task representing the running operation.
readonly ServiceProvider serviceProvider
The ServiceProvider containing Discord services.
override string BotMention
The string that indicates the IProvider was mentioned.
override async Task SendMessage(Message replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken)
Send a message to the IProvider. A Task representing the running operation.
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_channel_representation.html b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_channel_representation.html
index f92ad5f586..d9352de6a2 100644
--- a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_channel_representation.html
+++ b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_channel_representation.html
@@ -345,7 +345,7 @@ Properties
Definition at line 53 of file ChannelRepresentation.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl().
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_chat_manager.html b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_chat_manager.html
index 6d796291d0..1b93058e96 100644
--- a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_chat_manager.html
+++ b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_chat_manager.html
@@ -2284,7 +2284,7 @@ Here is the caller graph for this function:
Definition at line 29 of file ChatManager.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_providers_1_1_discord_provider.html b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_providers_1_1_discord_provider.html
index a109b986b4..c3c89f9514 100644
--- a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_providers_1_1_discord_provider.html
+++ b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_providers_1_1_discord_provider.html
@@ -588,7 +588,7 @@ Private Attributes
167 }
Many to many relationship for Models.RevisionInformation and Models.TestMerge.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
@@ -636,73 +636,73 @@ Here is the caller graph for this function:
Implements Tgstation.Server.Host.Components.Chat.Providers.Provider.
-Definition at line 557 of file DiscordProvider.cs.
- 558 {
-
559 try
-
560 {
-
-
562 {
-
-
564 throw new InvalidOperationException("Discord gateway still active!");
-
565
-
-
567 }
-
568
-
569 var gatewayCancellationToken =
gatewayCts.Token;
-
570 var gatewayClient =
serviceProvider.GetRequiredService<DiscordGatewayClient>();
-
571
-
572 Task<Result> localGatewayTask;
-
-
574
-
575 using var gatewayConnectionAbortRegistration = cancellationToken.Register(() =>
gatewayReadyTcs.TrySetCanceled());
-
576 gatewayCancellationToken.Register(() =>
Logger.LogTrace(
"Stopping gateway client..."));
-
577
-
578
-
579 localGatewayTask = gatewayClient.RunAsync(gatewayCancellationToken);
-
580 try
-
581 {
-
-
583
-
584 if (localGatewayTask.IsCompleted || cancellationToken.IsCancellationRequested)
-
-
586
-
587 var userClient =
serviceProvider.GetRequiredService<IDiscordRestUserAPI>();
-
588
-
589 using var localCombinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, gatewayCancellationToken);
-
590 var currentUserResult = await userClient.GetCurrentUserAsync(localCombinedCts.Token);
-
591 if (!currentUserResult.IsSuccess)
-
592 {
-
593 Logger.LogWarning(
"Unable to retrieve current user: {0}", currentUserResult.Error.Message);
-
-
595 }
+
Definition at line 567 of file DiscordProvider.cs.
+
568 {
+
569 try
+
570 {
+
+
572 {
+
+
574 throw new InvalidOperationException("Discord gateway still active!");
+
575
+
+
577 }
+
578
+
579 var gatewayCancellationToken =
gatewayCts.Token;
+
580 var gatewayClient =
serviceProvider.GetRequiredService<DiscordGatewayClient>();
+
581
+
582 Task<Result> localGatewayTask;
+
+
584
+
585 using var gatewayConnectionAbortRegistration = cancellationToken.Register(() =>
gatewayReadyTcs.TrySetCanceled());
+
586 gatewayCancellationToken.Register(() =>
Logger.LogTrace(
"Stopping gateway client..."));
+
587
+
588
+
589 localGatewayTask = gatewayClient.RunAsync(gatewayCancellationToken);
+
590 try
+
591 {
+
+
593
+
594 if (localGatewayTask.IsCompleted || cancellationToken.IsCancellationRequested)
+
596
-
-
-
599 }
-
600 finally
-
601 {
-
-
603 }
-
604 }
-
605 catch
-
606 {
-
607
-
608
-
-
610 throw;
-
611 }
-
612 }
+
597 var userClient =
serviceProvider.GetRequiredService<IDiscordRestUserAPI>();
+
598
+
599 using var localCombinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, gatewayCancellationToken);
+
600 var currentUserResult = await userClient.GetCurrentUserAsync(localCombinedCts.Token);
+
601 if (!currentUserResult.IsSuccess)
+
602 {
+
603 Logger.LogWarning(
"Unable to retrieve current user: {0}", currentUserResult.Error.Message);
+
+
605 }
+
606
+
+
+
609 }
+
610 finally
+
611 {
+
+
613 }
+
614 }
+
615 catch
+
616 {
+
617
+
618
+
+
620 throw;
+
621 }
+
622 }
string initialUserName
The bot's username at the time of connection.
Task< Result > gatewayTask
The Task representing the lifetime of the client.
Snowflake currentUserId
The bot's Snowflake.
CancellationTokenSource gatewayCts
The CancellationTokenSource for the gatewayTask.
TaskCompletionSource< object > gatewayReadyTcs
The TaskCompletionSource<TResult> for the initial gateway connection event.
-
override async Task DisconnectImpl(CancellationToken cancellationToken)
Gracefully disconnects the provider. A Task representing the running operation.
+
override async Task DisconnectImpl(CancellationToken cancellationToken)
Gracefully disconnects the provider. A Task representing the running operation.
ILogger< Provider > Logger
The ILogger for the Provider.
Operation exceptions thrown from the context of a Models.Job.
ErrorCode
Types of Response.ErrorMessageResponses that the API may return.
-
References Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.connectDisconnectLock, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.currentUserId, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.gatewayCts, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.gatewayReadyTcs, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.gatewayTask, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.initialUserName, Tgstation.Server.Host.Components.Chat.Providers.Provider.Logger, and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.serviceProvider.
+
References Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.connectDisconnectLock, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.currentUserId, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.gatewayCts, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.gatewayReadyTcs, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.gatewayTask, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.initialUserName, Tgstation.Server.Host.Components.Chat.Providers.Provider.Logger, and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.serviceProvider.
@@ -748,49 +748,39 @@ Here is the call graph for this function:
- Returns
- The parameter for sending a single IEmbed.
-
Definition at line 746 of file DiscordProvider.cs.
-
747 {
-
748 if (embed == null)
-
749 return default;
-
750
-
751 List<string> embedErrors = new List<string>();
-
752 Optional<Color> colour = default;
-
-
754 if (Int32.TryParse(embed.
Colour.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var argb))
-
755 colour = Color.FromArgb(argb);
-
756 else
-
757 embedErrors.Add(
-
758 String.Format(
-
759 CultureInfo.InvariantCulture,
-
760 "Invalid embed colour: {0}",
-
-
762
-
-
764 {
-
765 embedErrors.Add("Null or whitespace embed author name!");
-
766 embed.Author = null;
-
767 }
-
768
-
769 List<IEmbedField> fields = null;
-
-
771 {
-
772 fields = new List<IEmbedField>();
-
773 var i = -1;
-
774 foreach (var field
in embed.
Fields)
-
775 {
-
776 ++i;
-
777 var invalid = false;
-
778 if (String.IsNullOrWhiteSpace(field.Name))
-
779 {
-
780 embedErrors.Add(
-
781 String.Format(
-
782 CultureInfo.InvariantCulture,
-
783 "Null or whitespace field author at index {0}!",
-
784 i));
-
785 invalid = true;
-
786 }
-
787
-
788 if (String.IsNullOrWhiteSpace(field.Value))
+
Definition at line 756 of file DiscordProvider.cs.
+
757 {
+
758 if (embed == null)
+
759 return default;
+
760
+
761 List<string> embedErrors = new List<string>();
+
762 Optional<Color> colour = default;
+
+
764 if (Int32.TryParse(embed.
Colour.Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var argb))
+
765 colour = Color.FromArgb(argb);
+
766 else
+
767 embedErrors.Add(
+
768 String.Format(
+
769 CultureInfo.InvariantCulture,
+
770 "Invalid embed colour: {0}",
+
+
772
+
+
774 {
+
775 embedErrors.Add("Null or whitespace embed author name!");
+
776 embed.Author = null;
+
777 }
+
778
+
779 List<IEmbedField> fields = null;
+
+
781 {
+
782 fields = new List<IEmbedField>();
+
783 var i = -1;
+
784 foreach (var field
in embed.
Fields)
+
785 {
+
786 ++i;
+
787 var invalid = false;
+
788 if (String.IsNullOrWhiteSpace(field.Name))
789 {
790 embedErrors.Add(
791 String.Format(
@@ -800,120 +790,130 @@ Here is the call graph for this function:
795 invalid = true;
796 }
797
-
798 if (invalid)
-
799 continue;
-
800
-
801 fields.Add(new EmbedField(field.Name, field.Value)
-
802 {
-
803 IsInline = field.IsInline ?? default(Optional<bool>),
-
804 });
-
805 }
-
806 }
+
798 if (String.IsNullOrWhiteSpace(field.Value))
+
799 {
+
800 embedErrors.Add(
+
801 String.Format(
+
802 CultureInfo.InvariantCulture,
+
803 "Null or whitespace field author at index {0}!",
+
804 i));
+
805 invalid = true;
+
806 }
807
-
-
809 {
-
810 embedErrors.Add("Null or whitespace embed footer text!");
-
811 embed.Footer = null;
-
812 }
-
813
-
814 if (embed.
Image !=
null && String.IsNullOrWhiteSpace(embed.
Image.
Url))
-
815 {
-
816 embedErrors.Add("Null or whitespace embed image url!");
-
817 embed.Image = null;
-
818 }
-
819
-
-
821 {
-
822 embedErrors.Add("Null or whitespace embed thumbnail url!");
-
823 embed.Thumbnail = null;
-
824 }
-
825
-
826 Optional<DateTimeOffset> timestampOptional = default;
-
-
828 if (DateTimeOffset.TryParse(embed.
Timestamp, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var timestamp))
-
829 timestampOptional = timestamp.ToUniversalTime();
-
830 else
-
831 embedErrors.Add(
-
832 String.Format(
-
833 CultureInfo.InvariantCulture,
-
834 "Invalid embed timestamp: {0}",
-
-
836
-
837 var discordEmbed = new Embed
-
838 {
-
839 Author = embed.Author != null
-
-
841 {
-
842 IconUrl = embed.Author.IconUrl ?? default(Optional<string>),
-
843 ProxyIconUrl = embed.Author.ProxyIconUrl ?? default(Optional<string>),
-
844 Url = embed.Author.Url ?? default(Optional<string>),
-
845 }
-
846 : default(Optional<IEmbedAuthor>),
-
847 Colour = colour,
-
848 Description = embed.Description ?? default(Optional<string>),
-
849 Fields = fields ?? default(Optional<IReadOnlyList<IEmbedField>>),
-
850 Footer = embed.Footer != null
-
-
852 {
-
853 IconUrl = embed.Footer.IconUrl ?? default(Optional<string>),
-
854 ProxyIconUrl = embed.Footer.ProxyIconUrl ?? default(Optional<string>),
+
808 if (invalid)
+
809 continue;
+
810
+
811 fields.Add(new EmbedField(field.Name, field.Value)
+
812 {
+
813 IsInline = field.IsInline ?? default(Optional<bool>),
+
814 });
+
815 }
+
816 }
+
817
+
+
819 {
+
820 embedErrors.Add("Null or whitespace embed footer text!");
+
821 embed.Footer = null;
+
822 }
+
823
+
824 if (embed.
Image !=
null && String.IsNullOrWhiteSpace(embed.
Image.
Url))
+
825 {
+
826 embedErrors.Add("Null or whitespace embed image url!");
+
827 embed.Image = null;
+
828 }
+
829
+
+
831 {
+
832 embedErrors.Add("Null or whitespace embed thumbnail url!");
+
833 embed.Thumbnail = null;
+
834 }
+
835
+
836 Optional<DateTimeOffset> timestampOptional = default;
+
+
838 if (DateTimeOffset.TryParse(embed.
Timestamp, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var timestamp))
+
839 timestampOptional = timestamp.ToUniversalTime();
+
840 else
+
841 embedErrors.Add(
+
842 String.Format(
+
843 CultureInfo.InvariantCulture,
+
844 "Invalid embed timestamp: {0}",
+
+
846
+
847 var discordEmbed = new Embed
+
848 {
+
849 Author = embed.Author != null
+
+
851 {
+
852 IconUrl = embed.Author.IconUrl ?? default(Optional<string>),
+
853 ProxyIconUrl = embed.Author.ProxyIconUrl ?? default(Optional<string>),
+
854 Url = embed.Author.Url ?? default(Optional<string>),
855 }
-
856 : default,
-
857 Image = embed.Image != null
-
-
859 {
-
860 Width = embed.Image.Width ?? default(Optional<int>),
-
861 Height = embed.Image.Height ?? default(Optional<int>),
-
862 ProxyUrl = embed.Image.ProxyUrl ?? default(Optional<string>),
-
863 }
-
864 : default(Optional<IEmbedImage>),
-
-
866 ? new EmbedProvider
-
867 {
-
868 Name = embed.Provider.Name ?? default(Optional<string>),
-
869 Url = embed.Provider.Url ?? default(Optional<string>),
-
870 }
-
871 : default(Optional<IEmbedProvider>),
-
872 Thumbnail = embed.Thumbnail != null
-
-
874 {
-
875 Width = embed.Thumbnail.Width ?? default(Optional<int>),
-
876 Height = embed.Thumbnail.Height ?? default(Optional<int>),
-
877 ProxyUrl = embed.Thumbnail.ProxyUrl ?? default(Optional<string>),
-
878 }
-
879 : default(Optional<IEmbedThumbnail>),
-
880 Timestamp = timestampOptional,
-
881 Title = embed.Title ?? default(Optional<string>),
-
882 Url = embed.Url ?? default(Optional<string>),
-
883 Video = embed.Video != null
-
884 ? new EmbedVideo
-
885 {
-
886 Url = embed.Video.Url ?? default(Optional<string>),
-
887 Width = embed.Video.Width ?? default(Optional<int>),
-
888 Height = embed.Video.Height ?? default(Optional<int>),
-
889 ProxyUrl = embed.Video.ProxyUrl ?? default(Optional<string>),
-
890 }
-
891 : default(Optional<IEmbedVideo>),
-
892 };
-
893
-
894 var result = new List<IEmbed> { discordEmbed };
-
895
-
896 if (embedErrors.Count > 0)
-
897 {
-
898 var joinedErrors = String.Join(Environment.NewLine, embedErrors);
-
899 Logger.LogError(
"Embed description contains errors:{newLine}{issues}", Environment.NewLine, joinedErrors);
-
900 result.Add(new Embed
-
901 {
-
902 Title = "TGS Embed Errors",
-
903 Description = joinedErrors,
-
904 Colour = Color.Red,
-
905 Footer = new EmbedFooter("Please report this to your codebase's maintainers."),
-
906 Timestamp = DateTimeOffset.UtcNow,
-
907 });
-
908 }
-
909
-
910 return result;
-
911 }
+
856 : default(Optional<IEmbedAuthor>),
+
857 Colour = colour,
+
858 Description = embed.Description ?? default(Optional<string>),
+
859 Fields = fields ?? default(Optional<IReadOnlyList<IEmbedField>>),
+
860 Footer = embed.Footer != null
+
+
862 {
+
863 IconUrl = embed.Footer.IconUrl ?? default(Optional<string>),
+
864 ProxyIconUrl = embed.Footer.ProxyIconUrl ?? default(Optional<string>),
+
865 }
+
866 : default,
+
867 Image = embed.Image != null
+
+
869 {
+
870 Width = embed.Image.Width ?? default(Optional<int>),
+
871 Height = embed.Image.Height ?? default(Optional<int>),
+
872 ProxyUrl = embed.Image.ProxyUrl ?? default(Optional<string>),
+
873 }
+
874 : default(Optional<IEmbedImage>),
+
+
876 ? new EmbedProvider
+
877 {
+
878 Name = embed.Provider.Name ?? default(Optional<string>),
+
879 Url = embed.Provider.Url ?? default(Optional<string>),
+
880 }
+
881 : default(Optional<IEmbedProvider>),
+
882 Thumbnail = embed.Thumbnail != null
+
+
884 {
+
885 Width = embed.Thumbnail.Width ?? default(Optional<int>),
+
886 Height = embed.Thumbnail.Height ?? default(Optional<int>),
+
887 ProxyUrl = embed.Thumbnail.ProxyUrl ?? default(Optional<string>),
+
888 }
+
889 : default(Optional<IEmbedThumbnail>),
+
890 Timestamp = timestampOptional,
+
891 Title = embed.Title ?? default(Optional<string>),
+
892 Url = embed.Url ?? default(Optional<string>),
+
893 Video = embed.Video != null
+
894 ? new EmbedVideo
+
895 {
+
896 Url = embed.Video.Url ?? default(Optional<string>),
+
897 Width = embed.Video.Width ?? default(Optional<int>),
+
898 Height = embed.Video.Height ?? default(Optional<int>),
+
899 ProxyUrl = embed.Video.ProxyUrl ?? default(Optional<string>),
+
900 }
+
901 : default(Optional<IEmbedVideo>),
+
902 };
+
903
+
904 var result = new List<IEmbed> { discordEmbed };
+
905
+
906 if (embedErrors.Count > 0)
+
907 {
+
908 var joinedErrors = String.Join(Environment.NewLine, embedErrors);
+
909 Logger.LogError(
"Embed description contains errors:{newLine}{issues}", Environment.NewLine, joinedErrors);
+
910 result.Add(new Embed
+
911 {
+
912 Title = "TGS Embed Errors",
+
913 Description = joinedErrors,
+
914 Colour = Color.Red,
+
915 Footer = new EmbedFooter("Please report this to your codebase's maintainers."),
+
916 Timestamp = DateTimeOffset.UtcNow,
+
917 });
+
918 }
+
919
+
920 return result;
+
921 }
Provider(IJobManager jobManager, ILogger< Provider > logger, ChatBot chatBot)
Initializes a new instance of the Provider class.
ChatEmbedMedia Image
The ChatEmbedMedia for an image.
@@ -977,31 +977,31 @@ Here is the caller graph for this function:
Implements Tgstation.Server.Host.Components.Chat.Providers.Provider.
-
Definition at line 615 of file DiscordProvider.cs.
-
616 {
-
617 Task<Result> localGatewayTask;
-
618 CancellationTokenSource localGatewayCts;
-
-
620 {
-
-
-
-
-
625 if (localGatewayTask == null)
-
626 return;
-
627 }
-
628
-
629 localGatewayCts.Cancel();
-
630 var gatewayResult = await localGatewayTask;
-
631 if (!gatewayResult.IsSuccess)
-
632 Logger.LogWarning(
"Gateway issue: {0}", gatewayResult.Error.Message);
-
633
-
634 localGatewayCts.Dispose();
-
635 }
+
Definition at line 625 of file DiscordProvider.cs.
+
626 {
+
627 Task<Result> localGatewayTask;
+
628 CancellationTokenSource localGatewayCts;
+
+
630 {
+
+
+
+
+
635 if (localGatewayTask == null)
+
636 return;
+
637 }
+
638
+
639 localGatewayCts.Cancel();
+
640 var gatewayResult = await localGatewayTask;
+
641 if (!gatewayResult.IsSuccess)
+
642 Logger.LogWarning(
"Gateway issue: {0}", gatewayResult.Error.Message);
+
643
+
644 localGatewayCts.Dispose();
+
645 }
References Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.connectDisconnectLock, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.gatewayCts, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.gatewayTask, and Tgstation.Server.Host.Components.Chat.Providers.Provider.Logger.
-
Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect().
+
Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect().
@@ -1102,107 +1102,107 @@ Here is the caller graph for this function:
-
Definition at line 638 of file DiscordProvider.cs.
-
639 {
-
640 if (channels == null)
-
641 throw new ArgumentNullException(nameof(channels));
-
642
-
643 var remapRequired = false;
-
644
-
645 async Task<Tuple<Models.ChatChannel, ChannelRepresentation>> GetModelChannelFromDBChannel(Models.ChatChannel channelFromDB)
-
646 {
-
647 if (!channelFromDB.DiscordChannelId.HasValue)
-
648 throw new InvalidOperationException("ChatChannel missing DiscordChannelId!");
-
649
-
650 var channelId = channelFromDB.DiscordChannelId.Value;
-
651 string connectionName;
-
652 string friendlyName;
-
653 if (channelId == 0)
-
654 {
-
-
656 friendlyName = "(Unmapped accessible channels)";
-
657 }
-
658 else
-
659 {
-
660 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
-
661 var discordChannelResponse = await channelsClient.GetChannelAsync(new Snowflake(channelId), cancellationToken);
-
662 if (!discordChannelResponse.IsSuccess)
-
663 {
-
-
665 "Error retrieving discord channel {channelId}: {error} Inner: {innerError}",
-
666 channelId,
-
667 discordChannelResponse.Error.Message,
-
668 discordChannelResponse.Inner?.Error?.Message);
-
669 remapRequired = true;
-
670 return null;
-
671 }
-
672
-
673 var channelType = discordChannelResponse.Entity.Type;
-
674 if (channelType != ChannelType.GuildText && channelType != ChannelType.GuildAnnouncement)
-
675 {
-
676 Logger.LogWarning(
"Cound not map channel {channelId}! Incorrect type: {channelType}", channelId, discordChannelResponse.Entity.Type);
-
677 return null;
-
678 }
-
679
-
680 friendlyName = discordChannelResponse.Entity.Name.Value;
-
681 var guildId = discordChannelResponse.Entity.GuildID.Value;
+
Definition at line 648 of file DiscordProvider.cs.
+
649 {
+
650 if (channels == null)
+
651 throw new ArgumentNullException(nameof(channels));
+
652
+
653 var remapRequired = false;
+
654
+
655 async Task<Tuple<Models.ChatChannel, ChannelRepresentation>> GetModelChannelFromDBChannel(Models.ChatChannel channelFromDB)
+
656 {
+
657 if (!channelFromDB.DiscordChannelId.HasValue)
+
658 throw new InvalidOperationException("ChatChannel missing DiscordChannelId!");
+
659
+
660 var channelId = channelFromDB.DiscordChannelId.Value;
+
661 string connectionName;
+
662 string friendlyName;
+
663 if (channelId == 0)
+
664 {
+
+
666 friendlyName = "(Unmapped accessible channels)";
+
667 }
+
668 else
+
669 {
+
670 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
+
671 var discordChannelResponse = await channelsClient.GetChannelAsync(new Snowflake(channelId), cancellationToken);
+
672 if (!discordChannelResponse.IsSuccess)
+
673 {
+
+
675 "Error retrieving discord channel {channelId}: {error} Inner: {innerError}",
+
676 channelId,
+
677 discordChannelResponse.Error.Message,
+
678 discordChannelResponse.Inner?.Error?.Message);
+
679 remapRequired = true;
+
680 return null;
+
681 }
682
-
683 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
-
684 var guildsResponse = await guildsClient.GetGuildAsync(
-
685 guildId,
-
686 false,
-
687 cancellationToken);
-
688 if (!guildsResponse.IsSuccess)
-
689 {
-
-
691 "Error retrieving discord guild {guildID}: {error} Inner: {innerError}",
-
692 guildId,
-
693 guildsResponse.Error.Message,
-
694 guildsResponse.Inner?.Error?.Message);
-
695 remapRequired = true;
-
696 return null;
-
697 }
-
698
-
699 connectionName = guildsResponse.Entity.Name;
-
700 }
-
701
-
702 var channelModel = new ChannelRepresentation
-
703 {
-
704 RealId = channelId,
-
705 IsAdminChannel = channelFromDB.IsAdminChannel == true,
-
706 ConnectionName = connectionName,
-
707 FriendlyName = friendlyName,
-
708 IsPrivateChannel = false,
-
709 Tag = channelFromDB.Tag,
-
710 EmbedsSupported = true,
-
711 };
-
712
-
713 Logger.LogTrace(
"Mapped channel {0}: {1}", channelModel.RealId, channelModel.FriendlyName);
-
714 return Tuple.Create(channelFromDB, channelModel);
-
715 }
-
716
-
717 var tasks = channels
-
718 .Select(x => GetModelChannelFromDBChannel(x))
-
719 .ToList();
-
720
-
721 await Task.WhenAll(tasks);
+
683 var channelType = discordChannelResponse.Entity.Type;
+
684 if (channelType != ChannelType.GuildText && channelType != ChannelType.GuildAnnouncement)
+
685 {
+
686 Logger.LogWarning(
"Cound not map channel {channelId}! Incorrect type: {channelType}", channelId, discordChannelResponse.Entity.Type);
+
687 return null;
+
688 }
+
689
+
690 friendlyName = discordChannelResponse.Entity.Name.Value;
+
691 var guildId = discordChannelResponse.Entity.GuildID.Value;
+
692
+
693 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
+
694 var guildsResponse = await guildsClient.GetGuildAsync(
+
695 guildId,
+
696 false,
+
697 cancellationToken);
+
698 if (!guildsResponse.IsSuccess)
+
699 {
+
+
701 "Error retrieving discord guild {guildID}: {error} Inner: {innerError}",
+
702 guildId,
+
703 guildsResponse.Error.Message,
+
704 guildsResponse.Inner?.Error?.Message);
+
705 remapRequired = true;
+
706 return null;
+
707 }
+
708
+
709 connectionName = guildsResponse.Entity.Name;
+
710 }
+
711
+
712 var channelModel = new ChannelRepresentation
+
713 {
+
714 RealId = channelId,
+
715 IsAdminChannel = channelFromDB.IsAdminChannel == true,
+
716 ConnectionName = connectionName,
+
717 FriendlyName = friendlyName,
+
718 IsPrivateChannel = false,
+
719 Tag = channelFromDB.Tag,
+
720 EmbedsSupported = true,
+
721 };
722
-
723 var enumerator = tasks
-
724 .Select(x => x.Result)
-
725 .Where(x => x != null)
-
726 .ToList();
-
727
-
-
729 {
-
-
-
732 }
-
733
-
734 if (remapRequired)
-
-
736
-
737 return enumerator;
-
738 }
+
723 Logger.LogTrace(
"Mapped channel {0}: {1}", channelModel.RealId, channelModel.FriendlyName);
+
724 return Tuple.Create(channelFromDB, channelModel);
+
725 }
+
726
+
727 var tasks = channels
+
728 .Select(x => GetModelChannelFromDBChannel(x))
+
729 .ToList();
+
730
+
731 await Task.WhenAll(tasks);
+
732
+
733 var enumerator = tasks
+
734 .Select(x => x.Result)
+
735 .Where(x => x != null)
+
736 .ToList();
+
737
+
+
739 {
+
+
+
742 }
+
743
+
744 if (remapRequired)
+
+
746
+
747 return enumerator;
+
748 }
void EnqueueMessage(Message message)
Queues a message for NextMessage(CancellationToken).
References Tgstation.Server.Host.Components.Chat.Providers.Provider.EnqueueMessage(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.initialUserName, Tgstation.Server.Host.Components.Chat.Providers.Provider.Logger, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.mappedChannels, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.serviceProvider, and Tgstation.Server.Host.Components.Chat.ChannelRepresentation.Tag.
@@ -1251,7 +1251,7 @@ Here is the call graph for this function:
- Returns
- The normalized mention string.
-
Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
+
Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
@@ -1292,116 +1292,116 @@ Here is the caller graph for this function:
-
Definition at line 434 of file DiscordProvider.cs.
-
435 {
-
436 if (messageCreateEvent == null)
-
437 throw new ArgumentNullException(nameof(messageCreateEvent));
-
438
-
439 if ((messageCreateEvent.Type != MessageType.Default
-
440 && messageCreateEvent.Type != MessageType.InlineReply)
-
-
442 return Result.FromSuccess();
-
443
-
444 var messageReference = new MessageReference
-
445 {
-
446 ChannelID = messageCreateEvent.ChannelID,
-
447 GuildID = messageCreateEvent.GuildID,
-
448 MessageID = messageCreateEvent.ID,
-
449 FailIfNotExists = false,
-
450 };
-
451
-
452 if (
basedMeme && messageCreateEvent.Content.Equals(
"Based on what?", StringComparison.OrdinalIgnoreCase))
-
453 {
-
454
-
-
456 new DiscordMessage
-
457 {
-
458 MessageReference = messageReference,
-
459 },
-
-
461 {
-
462 Text = "https://youtu.be/LrNu-SuFF_o",
-
463 },
-
464 messageCreateEvent.ChannelID.Value,
-
465 default);
-
466 return Result.FromSuccess();
-
467 }
-
468
-
469 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
-
470 var channelResponse = await channelsClient.GetChannelAsync(messageCreateEvent.ChannelID, cancellationToken);
-
471 if (!channelResponse.IsSuccess)
-
472 {
-
-
474 "Failed to get channel {0} in response to message {1}!",
-
475 messageCreateEvent.ChannelID,
-
476 messageCreateEvent.ID);
-
477
-
478
-
479 return Result.FromSuccess();
-
480 }
-
481
-
482 var pm = channelResponse.Entity.Type == ChannelType.DM || channelResponse.Entity.Type == ChannelType.GroupDM;
-
483 var shouldNotAnswer = !pm;
-
484 if (shouldNotAnswer)
-
-
+
Definition at line 444 of file DiscordProvider.cs.
+
445 {
+
446 if (messageCreateEvent == null)
+
447 throw new ArgumentNullException(nameof(messageCreateEvent));
+
448
+
449 if ((messageCreateEvent.Type != MessageType.Default
+
450 && messageCreateEvent.Type != MessageType.InlineReply)
+
+
452 return Result.FromSuccess();
+
453
+
454 var messageReference = new MessageReference
+
455 {
+
456 ChannelID = messageCreateEvent.ChannelID,
+
457 GuildID = messageCreateEvent.GuildID,
+
458 MessageID = messageCreateEvent.ID,
+
459 FailIfNotExists = false,
+
460 };
+
461
+
462 if (
basedMeme && messageCreateEvent.Content.Equals(
"Based on what?", StringComparison.OrdinalIgnoreCase))
+
463 {
+
464
+
+
466 new DiscordMessage
+
467 {
+
468 MessageReference = messageReference,
+
469 },
+
+
471 {
+
472 Text = "https://youtu.be/LrNu-SuFF_o",
+
473 },
+
474 messageCreateEvent.ChannelID.Value,
+
475 default);
+
476 return Result.FromSuccess();
+
477 }
+
478
+
479 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
+
480 var channelResponse = await channelsClient.GetChannelAsync(messageCreateEvent.ChannelID, cancellationToken);
+
481 if (!channelResponse.IsSuccess)
+
482 {
+
+
484 "Failed to get channel {0} in response to message {1}!",
+
485 messageCreateEvent.ChannelID,
+
486 messageCreateEvent.ID);
487
-
-
489 var mentionedUs = messageCreateEvent.Mentions.Any(x => x.ID ==
currentUserId)
-
490 || (!shouldNotAnswer && content.Split(' ').First().Equals(ChatManager.CommonMention, StringComparison.OrdinalIgnoreCase));
+
488
+
489 return Result.FromSuccess();
+
490 }
491
-
492 if (shouldNotAnswer)
-
493 {
-
494 if (mentionedUs)
-
-
496 "Ignoring mention from {0} ({1}) by {2} ({3}). Channel not mapped!",
-
497 messageCreateEvent.ChannelID,
-
498 channelResponse.Entity.Name,
-
499 messageCreateEvent.Author.ID,
-
500 messageCreateEvent.Author.Username);
+
492 var pm = channelResponse.Entity.Type == ChannelType.DM || channelResponse.Entity.Type == ChannelType.GroupDM;
+
493 var shouldNotAnswer = !pm;
+
494 if (shouldNotAnswer)
+
+
+
497
+
+
499 var mentionedUs = messageCreateEvent.Mentions.Any(x => x.ID ==
currentUserId)
+
500 || (!shouldNotAnswer && content.Split(' ').First().Equals(ChatManager.CommonMention, StringComparison.OrdinalIgnoreCase));
501
-
502 return Result.FromSuccess();
-
503 }
-
504
-
505 string guildName = "UNKNOWN";
-
506 if (!pm)
-
507 {
-
508 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
-
509 var messageGuildResponse = await guildsClient.GetGuildAsync(messageCreateEvent.GuildID.Value, false, cancellationToken);
-
510 if (messageGuildResponse.IsSuccess)
-
511 guildName = messageGuildResponse.Entity.Name;
-
512 else
-
-
514 "Failed to get channel {0} in response to message {1}!",
-
515 messageCreateEvent.ChannelID,
-
516 messageCreateEvent.ID);
-
517 }
-
518
-
519 var result = new DiscordMessage
-
520 {
-
521 MessageReference = messageReference,
-
522 Content = content,
-
-
524 {
-
525 RealId = messageCreateEvent.Author.ID.Value,
-
526 Channel = new ChannelRepresentation
-
527 {
-
528 RealId = messageCreateEvent.ChannelID.Value,
-
529 IsPrivateChannel = pm,
-
530 ConnectionName = pm ? messageCreateEvent.Author.Username : guildName,
-
531 FriendlyName = channelResponse.Entity.
Name.Value,
-
532 EmbedsSupported = true,
-
533
-
534
-
535 },
-
536 FriendlyName = messageCreateEvent.Author.Username,
-
-
538 },
-
539 };
-
540
-
-
542 return Result.FromSuccess();
-
543 }
+
502 if (shouldNotAnswer)
+
503 {
+
504 if (mentionedUs)
+
+
506 "Ignoring mention from {0} ({1}) by {2} ({3}). Channel not mapped!",
+
507 messageCreateEvent.ChannelID,
+
508 channelResponse.Entity.Name,
+
509 messageCreateEvent.Author.ID,
+
510 messageCreateEvent.Author.Username);
+
511
+
512 return Result.FromSuccess();
+
513 }
+
514
+
515 string guildName = "UNKNOWN";
+
516 if (!pm)
+
517 {
+
518 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
+
519 var messageGuildResponse = await guildsClient.GetGuildAsync(messageCreateEvent.GuildID.Value, false, cancellationToken);
+
520 if (messageGuildResponse.IsSuccess)
+
521 guildName = messageGuildResponse.Entity.Name;
+
522 else
+
+
524 "Failed to get channel {0} in response to message {1}!",
+
525 messageCreateEvent.ChannelID,
+
526 messageCreateEvent.ID);
+
527 }
+
528
+
529 var result = new DiscordMessage
+
530 {
+
531 MessageReference = messageReference,
+
532 Content = content,
+
+
534 {
+
535 RealId = messageCreateEvent.Author.ID.Value,
+
536 Channel = new ChannelRepresentation
+
537 {
+
538 RealId = messageCreateEvent.ChannelID.Value,
+
539 IsPrivateChannel = pm,
+
540 ConnectionName = pm ? messageCreateEvent.Author.Username : guildName,
+
541 FriendlyName = channelResponse.Entity.
Name.Value,
+
542 EmbedsSupported = true,
+
543
+
544
+
545 },
+
546 FriendlyName = messageCreateEvent.Author.Username,
+
+
548 },
+
549 };
+
550
+
+
552 return Result.FromSuccess();
+
553 }
static string NormalizeMentions(string fromDiscord)
Normalize a discord mention string.
override async Task SendMessage(Message replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken)
Send a message to the IProvider. A Task representing the running operation.
@@ -1452,15 +1452,15 @@ Here is the call graph for this function:
-
Definition at line 546 of file DiscordProvider.cs.
-
Definition at line 224 of file DiscordProvider.cs.
225 {
226 Optional<IMessageReference> replyToReference = default;
-
227 if (replyTo != null && replyTo is DiscordMessage discordMessage)
-
228 {
-
229 replyToReference = discordMessage.MessageReference;
-
230 }
-
231
-
-
233
-
234 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
-
235 async Task SendToChannel(Snowflake channelId)
-
236 {
-
237 var result = await channelsClient.CreateMessageAsync(
-
238 channelId,
-
-
240 embeds: embeds,
-
241 messageReference: replyToReference,
-
242 ct: cancellationToken);
-
243
-
244 if (!result.IsSuccess)
-
-
246 "Failed to send to channel {0}: {1}",
-
247 channelId,
-
248 result.Error);
-
249 }
-
250
-
251 try
-
252 {
-
253 if (channelId == 0)
-
254 {
-
255 var usersClient =
serviceProvider.GetRequiredService<IDiscordRestUserAPI>();
-
256 var currentGuildsResponse = await usersClient.GetCurrentUserGuildsAsync(ct: cancellationToken);
-
257 if (!currentGuildsResponse.IsSuccess)
-
258 {
-
-
260 "Error retrieving current discord guilds: {0}",
-
261 currentGuildsResponse.Error.Message);
-
262 return;
-
263 }
-
264
-
265 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
-
266
-
267 var guildsChannelsTasks = currentGuildsResponse.Entity.Select(
-
268 guild => guildsClient.GetGuildChannelsAsync(guild.ID.Value, cancellationToken));
-
269
-
270 await Task.WhenAll(guildsChannelsTasks);
-
271
-
272 var unmappedTextChannels = guildsChannelsTasks
-
273 .Select(task => task.Result)
-
274 .SelectMany(guildChannels => guildChannels.Entity)
-
275 .Where(guildChannel => guildChannel.Type == ChannelType.GuildText);
+
227 Optional<IAllowedMentions> allowedMentions = default;
+
228 if (replyTo != null && replyTo is DiscordMessage discordMessage)
+
229 {
+
230 replyToReference = discordMessage.MessageReference;
+
231 allowedMentions = new AllowedMentions(
+
232 Parse: new List<MentionType>
+
233 {
+
234 MentionType.Everyone,
+
235 MentionType.Roles,
+
236 MentionType.Users,
+
237 },
+
238 MentionRepliedUser: false);
+
239 }
+
240
+
+
242
+
243 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
+
244 async Task SendToChannel(Snowflake channelId)
+
245 {
+
246 var result = await channelsClient.CreateMessageAsync(
+
247 channelId,
+
+
249 embeds: embeds,
+
250 messageReference: replyToReference,
+
251 allowedMentions: allowedMentions,
+
252 ct: cancellationToken);
+
253
+
254 if (!result.IsSuccess)
+
+
256 "Failed to send to channel {0}: {1}",
+
257 channelId,
+
258 result.Error);
+
259 }
+
260
+
261 try
+
262 {
+
263 if (channelId == 0)
+
264 {
+
265 var usersClient =
serviceProvider.GetRequiredService<IDiscordRestUserAPI>();
+
266 var currentGuildsResponse = await usersClient.GetCurrentUserGuildsAsync(ct: cancellationToken);
+
267 if (!currentGuildsResponse.IsSuccess)
+
268 {
+
+
270 "Error retrieving current discord guilds: {0}",
+
271 currentGuildsResponse.Error.Message);
+
272 return;
+
273 }
+
274
+
275 var guildsClient =
serviceProvider.GetRequiredService<IDiscordRestGuildAPI>();
276
-
-
278 unmappedTextChannels = unmappedTextChannels
-
-
280 .ToList();
+
277 var guildsChannelsTasks = currentGuildsResponse.Entity.Select(
+
278 guild => guildsClient.GetGuildChannelsAsync(guild.ID.Value, cancellationToken));
+
279
+
280 await Task.WhenAll(guildsChannelsTasks);
281
-
282
-
283 if (unmappedTextChannels.Any())
-
284 {
-
285 Logger.LogTrace(
"Dispatching to {0} unmapped channels...", unmappedTextChannels.Count());
-
286 await Task.WhenAll(
-
287 unmappedTextChannels.Select(
-
288 x => SendToChannel(x.ID)));
-
289 }
-
290
-
291 return;
-
292 }
-
293
-
294 await SendToChannel(new Snowflake(channelId));
-
295 }
-
296 catch (Exception e)
-
297 {
-
298 if (e is OperationCanceledException)
-
299 cancellationToken.ThrowIfCancellationRequested();
-
300 Logger.LogWarning(e,
"Error sending discord message!");
-
301 }
-
302 }
-
Optional< IReadOnlyList< IEmbed > > ConvertEmbed(ChatEmbed embed)
Convert a ChatEmbed to an IEmbed parameters.
+
282 var unmappedTextChannels = guildsChannelsTasks
+
283 .Select(task => task.Result)
+
284 .SelectMany(guildChannels => guildChannels.Entity)
+
285 .Where(guildChannel => guildChannel.Type == ChannelType.GuildText);
+
286
+
+
288 unmappedTextChannels = unmappedTextChannels
+
+
290 .ToList();
+
291
+
292
+
293 if (unmappedTextChannels.Any())
+
294 {
+
295 Logger.LogTrace(
"Dispatching to {0} unmapped channels...", unmappedTextChannels.Count());
+
296 await Task.WhenAll(
+
297 unmappedTextChannels.Select(
+
298 x => SendToChannel(x.ID)));
+
299 }
+
300
+
301 return;
+
302 }
+
303
+
304 await SendToChannel(new Snowflake(channelId));
+
305 }
+
306 catch (Exception e)
+
307 {
+
308 if (e is OperationCanceledException)
+
309 cancellationToken.ThrowIfCancellationRequested();
+
310 Logger.LogWarning(e,
"Error sending discord message!");
+
311 }
+
312 }
+
Optional< IReadOnlyList< IEmbed > > ConvertEmbed(ChatEmbed embed)
Convert a ChatEmbed to an IEmbed parameters.
ChatEmbed Embed
The ChatEmbed.
string Text
The message string.
-
References Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed(), Tgstation.Server.Host.Components.Interop.MessageContent.Embed, Tgstation.Server.Host.Components.Chat.Providers.Provider.Logger, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.mappedChannels, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.serviceProvider, and Tgstation.Server.Host.Components.Interop.MessageContent.Text.
+
References Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed(), Tgstation.Server.Host.Components.Interop.MessageContent.Embed, Tgstation.Server.Host.Components.Chat.Providers.Provider.Logger, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.mappedChannels, Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.serviceProvider, and Tgstation.Server.Host.Components.Interop.MessageContent.Text.
-
Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
+
Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
@@ -1697,125 +1707,125 @@ Here is the caller graph for this function:
-
Definition at line 305 of file DiscordProvider.cs.
-
314 {
-
315 localCommitPushed |= revisionInformation.CommitSha == revisionInformation.OriginCommitSha;
-
316
-
317 var fields =
BuildUpdateEmbedFields(revisionInformation, byondVersion, gitHubOwner, gitHubRepo, localCommitPushed);
-
-
319 {
-
320 Url = "https://github.com/tgstation/tgstation-server",
-
321 IconUrl = "https://avatars0.githubusercontent.com/u/1363778?s=280&v=4",
-
322 };
-
323 var embed = new Embed
-
324 {
-
-
326 Colour = Color.FromArgb(0xF1, 0xC4, 0x0F),
-
327 Description = "TGS has begun deploying active repository code to production.",
-
328 Fields = fields,
-
329 Title = "Code Deployment",
-
330 Footer = new EmbedFooter(
-
331 $"In progress...{(estimatedCompletionTime.HasValue ? " ETA" : String.Empty)}"),
-
332 Timestamp = estimatedCompletionTime ?? default,
-
333 };
-
334
-
335 Logger.LogTrace(
"Attempting to post deploy embed to channel {0}...", channelId);
-
336 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
-
337
-
338 var messageResponse = await channelsClient.CreateMessageAsync(
-
339 new Snowflake(channelId),
-
340 "DM: Deployment in Progress...",
-
341 embeds: new List<IEmbed> { embed },
-
342 ct: cancellationToken)
-
343 ;
+
Definition at line 315 of file DiscordProvider.cs.
+
324 {
+
325 localCommitPushed |= revisionInformation.CommitSha == revisionInformation.OriginCommitSha;
+
326
+
327 var fields =
BuildUpdateEmbedFields(revisionInformation, byondVersion, gitHubOwner, gitHubRepo, localCommitPushed);
+
+
329 {
+
330 Url = "https://github.com/tgstation/tgstation-server",
+
331 IconUrl = "https://avatars0.githubusercontent.com/u/1363778?s=280&v=4",
+
332 };
+
333 var embed = new Embed
+
334 {
+
+
336 Colour = Color.FromArgb(0xF1, 0xC4, 0x0F),
+
337 Description = "TGS has begun deploying active repository code to production.",
+
338 Fields = fields,
+
339 Title = "Code Deployment",
+
340 Footer = new EmbedFooter(
+
341 $"In progress...{(estimatedCompletionTime.HasValue ? " ETA" : String.Empty)}"),
+
342 Timestamp = estimatedCompletionTime ?? default,
+
343 };
344
-
345 if (!messageResponse.IsSuccess)
-
346 Logger.LogWarning(
"Failed to post deploy embed to channel {0}: {1}", channelId, messageResponse.Error.Message);
+
345 Logger.LogTrace(
"Attempting to post deploy embed to channel {0}...", channelId);
+
346 var channelsClient =
serviceProvider.GetRequiredService<IDiscordRestChannelAPI>();
347
-
348 return async (errorMessage, dreamMakerOutput) =>
-
349 {
-
350 var completionString = errorMessage == null ? "Succeeded" : "Failed";
-
351
-
352 embed = new Embed
-
353 {
-
354 Author = embed.Author,
-
355 Colour = errorMessage == null ? Color.Green : Color.Red,
-
356 Description = errorMessage == null
-
357 ? "The deployment completed successfully and will be available at the next server reboot."
-
358 : "The deployment failed.",
-
359 Fields = fields,
-
360 Title = embed.Title,
-
361 Footer = new EmbedFooter(
-
362 completionString),
-
363 Timestamp = DateTimeOffset.UtcNow,
-
364 };
-
365
-
-
367 {
-
368 DiscordDMOutputDisplayType.Always => true,
-
369 DiscordDMOutputDisplayType.Never => false,
-
370 DiscordDMOutputDisplayType.OnError => errorMessage != null,
-
371 _ => throw new InvalidOperationException($"Invalid DiscordDMOutputDisplayType: {outputDisplayType}"),
-
372 };
-
373
-
374 if (dreamMakerOutput != null)
-
375 {
-
376
-
377 const int MaxFieldValueLength = 1024;
-
378 showDMOutput = showDMOutput && dreamMakerOutput.Length < MaxFieldValueLength - (6 + Environment.NewLine.Length);
-
379 if (showDMOutput)
-
380 fields.Add(new EmbedField(
-
381 "DreamMaker Output",
-
382 $"```{Environment.NewLine}{dreamMakerOutput}{Environment.NewLine}```",
-
383 false));
-
384 }
-
385
-
386 if (errorMessage != null)
-
387 fields.Add(new EmbedField(
-
388 "Error Message",
-
389 errorMessage,
-
390 false));
-
391
-
392 var updatedMessage = $"DM: Deployment {completionString}!";
-
393
-
394 async Task CreateUpdatedMessage()
-
395 {
-
396 var createUpdatedMessageResponse = await channelsClient.CreateMessageAsync(
-
397 new Snowflake(channelId),
-
398 updatedMessage,
-
399 embeds: new List<IEmbed> { embed },
-
400 ct: cancellationToken)
-
401 ;
-
402
-
403 if (!createUpdatedMessageResponse.IsSuccess)
-
-
405 "Creating updated deploy embed failed! Error: {0}",
-
406 createUpdatedMessageResponse.Error.Message);
-
407 }
-
408
-
409 if (!messageResponse.IsSuccess)
-
410 await CreateUpdatedMessage();
-
411 else
-
412 {
-
413 var editResponse = await channelsClient.EditMessageAsync(
-
414 new Snowflake(channelId),
-
415 messageResponse.Entity.ID,
-
416 updatedMessage,
-
417 embeds: new List<IEmbed> { embed },
-
418 ct: cancellationToken)
-
419 ;
-
420
-
421 if (!editResponse.IsSuccess)
-
422 {
-
-
424 "Updating deploy embed {0} failed, attempting new post! Error: {1}",
-
425 messageResponse.Entity.ID,
-
426 editResponse.Error.Message);
-
427 await CreateUpdatedMessage();
-
428 }
-
429 }
-
430 };
-
431 }
+
348 var messageResponse = await channelsClient.CreateMessageAsync(
+
349 new Snowflake(channelId),
+
350 "DM: Deployment in Progress...",
+
351 embeds: new List<IEmbed> { embed },
+
352 ct: cancellationToken)
+
353 ;
+
354
+
355 if (!messageResponse.IsSuccess)
+
356 Logger.LogWarning(
"Failed to post deploy embed to channel {0}: {1}", channelId, messageResponse.Error.Message);
+
357
+
358 return async (errorMessage, dreamMakerOutput) =>
+
359 {
+
360 var completionString = errorMessage == null ? "Succeeded" : "Failed";
+
361
+
362 embed = new Embed
+
363 {
+
364 Author = embed.Author,
+
365 Colour = errorMessage == null ? Color.Green : Color.Red,
+
366 Description = errorMessage == null
+
367 ? "The deployment completed successfully and will be available at the next server reboot."
+
368 : "The deployment failed.",
+
369 Fields = fields,
+
370 Title = embed.Title,
+
371 Footer = new EmbedFooter(
+
372 completionString),
+
373 Timestamp = DateTimeOffset.UtcNow,
+
374 };
+
375
+
+
377 {
+
378 DiscordDMOutputDisplayType.Always => true,
+
379 DiscordDMOutputDisplayType.Never => false,
+
380 DiscordDMOutputDisplayType.OnError => errorMessage != null,
+
381 _ => throw new InvalidOperationException($"Invalid DiscordDMOutputDisplayType: {outputDisplayType}"),
+
382 };
+
383
+
384 if (dreamMakerOutput != null)
+
385 {
+
386
+
387 const int MaxFieldValueLength = 1024;
+
388 showDMOutput = showDMOutput && dreamMakerOutput.Length < MaxFieldValueLength - (6 + Environment.NewLine.Length);
+
389 if (showDMOutput)
+
390 fields.Add(new EmbedField(
+
391 "DreamMaker Output",
+
392 $"```{Environment.NewLine}{dreamMakerOutput}{Environment.NewLine}```",
+
393 false));
+
394 }
+
395
+
396 if (errorMessage != null)
+
397 fields.Add(new EmbedField(
+
398 "Error Message",
+
399 errorMessage,
+
400 false));
+
401
+
402 var updatedMessage = $"DM: Deployment {completionString}!";
+
403
+
404 async Task CreateUpdatedMessage()
+
405 {
+
406 var createUpdatedMessageResponse = await channelsClient.CreateMessageAsync(
+
407 new Snowflake(channelId),
+
408 updatedMessage,
+
409 embeds: new List<IEmbed> { embed },
+
410 ct: cancellationToken)
+
411 ;
+
412
+
413 if (!createUpdatedMessageResponse.IsSuccess)
+
+
415 "Creating updated deploy embed failed! Error: {0}",
+
416 createUpdatedMessageResponse.Error.Message);
+
417 }
+
418
+
419 if (!messageResponse.IsSuccess)
+
420 await CreateUpdatedMessage();
+
421 else
+
422 {
+
423 var editResponse = await channelsClient.EditMessageAsync(
+
424 new Snowflake(channelId),
+
425 messageResponse.Entity.ID,
+
426 updatedMessage,
+
427 embeds: new List<IEmbed> { embed },
+
428 ct: cancellationToken)
+
429 ;
+
430
+
431 if (!editResponse.IsSuccess)
+
432 {
+
+
434 "Updating deploy embed {0} failed, attempting new post! Error: {1}",
+
435 messageResponse.Entity.ID,
+
436 editResponse.Error.Message);
+
437 await CreateUpdatedMessage();
+
438 }
+
439 }
+
440 };
+
441 }
static List< IEmbedField > BuildUpdateEmbedFields(Models.RevisionInformation revisionInformation, Version byondVersion, string gitHubOwner, string gitHubRepo, bool localCommitPushed)
Create a List<T> of IEmbedFields for a discord update embed.
@@ -1857,7 +1867,7 @@ Here is the call graph for this function:
Definition at line 53 of file DiscordProvider.cs.
-
Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
+
Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
@@ -1885,7 +1895,7 @@ Here is the call graph for this function:
Definition at line 73 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
@@ -1913,7 +1923,7 @@ Here is the call graph for this function:
Definition at line 68 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider().
@@ -1941,7 +1951,7 @@ Here is the call graph for this function:
Definition at line 103 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
@@ -1969,7 +1979,7 @@ Here is the call graph for this function:
Definition at line 78 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
@@ -2025,7 +2035,7 @@ Here is the call graph for this function:
Definition at line 88 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisposeAsync().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisposeAsync().
@@ -2053,7 +2063,7 @@ Here is the call graph for this function:
Definition at line 93 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
@@ -2081,7 +2091,7 @@ Here is the call graph for this function:
Definition at line 98 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl().
@@ -2109,7 +2119,7 @@ Here is the call graph for this function:
Definition at line 108 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl().
@@ -2137,7 +2147,7 @@ Here is the call graph for this function:
Definition at line 63 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendMessage().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendMessage().
@@ -2165,7 +2175,7 @@ Here is the call graph for this function:
Definition at line 83 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
@@ -2193,7 +2203,7 @@ Here is the call graph for this function:
Definition at line 58 of file DiscordProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisposeAsync(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendMessage(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DiscordProvider(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisposeAsync(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendMessage(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage().
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_providers_1_1_provider.html b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_providers_1_1_provider.html
index 659410103e..85738a7e4b 100644
--- a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_providers_1_1_provider.html
+++ b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_chat_1_1_providers_1_1_provider.html
@@ -633,7 +633,7 @@ Here is the call graph for this function:
References Tgstation.Server.Host.Components.Chat.Providers.Provider.Logger, Tgstation.Server.Host.Components.Chat.Providers.Provider.messageQueue, and Tgstation.Server.Host.Components.Chat.Providers.Provider.nextMessage.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.HandleMessage(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl(), Tgstation.Server.Host.Components.Chat.Providers.Provider.ReconnectionLoop(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.HandleMessage(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl(), Tgstation.Server.Host.Components.Chat.Providers.Provider.ReconnectionLoop(), and Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync().
@@ -1652,7 +1652,7 @@ Here is the caller graph for this function:
Definition at line 30 of file Provider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed(), Tgstation.Server.Host.Components.Chat.Providers.Provider.Disconnect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.DisconnectImpl(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisposeAsync(), Tgstation.Server.Host.Components.Chat.Providers.Provider.DisposeAsync(), Tgstation.Server.Host.Components.Chat.Providers.Provider.EnqueueMessage(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.HardDisconnect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.NonBlockingListen(), Tgstation.Server.Host.Components.Chat.Providers.Provider.Provider(), Tgstation.Server.Host.Components.Chat.Providers.Provider.ReconnectionLoop(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.SaslAuthenticate(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendMessage(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.SendMessage(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage(), and Tgstation.Server.Host.Components.Chat.Providers.Provider.StopReconnectionTimer().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.Connect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed(), Tgstation.Server.Host.Components.Chat.Providers.Provider.Disconnect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisconnectImpl(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.DisconnectImpl(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.DisposeAsync(), Tgstation.Server.Host.Components.Chat.Providers.Provider.DisposeAsync(), Tgstation.Server.Host.Components.Chat.Providers.Provider.EnqueueMessage(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.HardDisconnect(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.MapChannelsImpl(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.NonBlockingListen(), Tgstation.Server.Host.Components.Chat.Providers.Provider.Provider(), Tgstation.Server.Host.Components.Chat.Providers.Provider.ReconnectionLoop(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.RespondAsync(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.SaslAuthenticate(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendMessage(), Tgstation.Server.Host.Components.Chat.Providers.IrcProvider.SendMessage(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage(), and Tgstation.Server.Host.Components.Chat.Providers.Provider.StopReconnectionTimer().
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed.html b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed.html
index 7e492e6009..05fa29496e 100644
--- a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed.html
+++ b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed.html
@@ -154,7 +154,7 @@ Properties
Definition at line 65 of file ChatEmbed.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
@@ -183,7 +183,7 @@ Properties
Definition at line 35 of file ChatEmbed.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
@@ -239,7 +239,7 @@ Properties
Definition at line 70 of file ChatEmbed.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
@@ -268,7 +268,7 @@ Properties
Definition at line 40 of file ChatEmbed.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
@@ -297,7 +297,7 @@ Properties
Definition at line 45 of file ChatEmbed.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
@@ -353,7 +353,7 @@ Properties
Definition at line 50 of file ChatEmbed.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
@@ -382,7 +382,7 @@ Properties
Definition at line 30 of file ChatEmbed.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_footer.html b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_footer.html
index a39b3116ba..8023f11980 100644
--- a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_footer.html
+++ b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_footer.html
@@ -181,7 +181,7 @@ Properties
Definition at line 11 of file ChatEmbedFooter.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_media.html b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_media.html
index 9f635e41d6..afaf81899e 100644
--- a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_media.html
+++ b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_media.html
@@ -184,7 +184,7 @@ Properties
Definition at line 12 of file ChatEmbedMedia.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
diff --git a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_provider.html b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_provider.html
index 1f38a7db9e..c67f23ee4b 100644
--- a/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_provider.html
+++ b/class_tgstation_1_1_server_1_1_host_1_1_components_1_1_interop_1_1_chat_embed_provider.html
@@ -133,7 +133,7 @@ Properties
Definition at line 11 of file ChatEmbedProvider.cs.
-Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
+Referenced by Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.ConvertEmbed().
diff --git a/interface_tgstation_1_1_server_1_1_host_1_1_system_1_1_i_assembly_information_provider.html b/interface_tgstation_1_1_server_1_1_host_1_1_system_1_1_i_assembly_information_provider.html
index 5273fc34b1..d840f24afc 100644
--- a/interface_tgstation_1_1_server_1_1_host_1_1_system_1_1_i_assembly_information_provider.html
+++ b/interface_tgstation_1_1_server_1_1_host_1_1_system_1_1_i_assembly_information_provider.html
@@ -271,7 +271,7 @@ Properties
Definition at line 25 of file IAssemblyInformationProvider.cs.
-Referenced by Tgstation.Server.Host.Setup.SetupWizard.ConfigureDatabase(), Tgstation.Server.Host.Configuration.FileLoggingConfiguration.GetFullLogDirectory(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage(), and Tgstation.Server.Host.Extensions.ApplicationBuilderExtensions.UseServerBranding().
+Referenced by Tgstation.Server.Host.Setup.SetupWizard.ConfigureDatabase(), Tgstation.Server.Host.Configuration.FileLoggingConfiguration.GetFullLogDirectory(), Tgstation.Server.Host.Components.Chat.Providers.DiscordProvider.SendUpdateMessage(), and Tgstation.Server.Host.Extensions.ApplicationBuilderExtensions.UseServerBranding().