Example #1
0
        public async Task Cloud([Remainder] string arguments = null)
        {
            var args = CommandHelper.ParseArgs(arguments, new
            {
                ClusterKey = "",
                Backup     = 0L,
                Stash      = 0L,
                Pop        = 0L,
                Delete     = 0L,
                List       = 0L,
                Details    = 0L,
                Restore    = 0L,
                Target1    = "",
                Target2    = "",
                Skip       = 0
            }, x =>
                                               x.For(y => y.ClusterKey, noPrefix: true)
                                               .For(y => y.Target1, noPrefix: true)
                                               .For(y => y.Target2, noPrefix: true));

            var sb           = new StringBuilder();
            var r_allowedExt = new Regex(@"^(?!tmpprofile)([a-z0-9])+$", RegexOptions.Singleline | RegexOptions.IgnoreCase);

            //for details and restore commands, get hashes from target1 and target2
            int?backupHash = null, cloudSaveHash = null;

            if (args.Details > 0 || args.Restore > 0)
            {
                try
                {
                    backupHash = !string.IsNullOrWhiteSpace(args.Target1) ? (int?)Convert.ToInt32(args.Target1, 16) : null;
                }
                catch { /*ignore exceptions*/ }
            }
            if (args.Restore > 0)
            {
                try
                {
                    cloudSaveHash = !string.IsNullOrWhiteSpace(args.Target2) ? (int?)Convert.ToInt32(args.Target2, 16) : null;
                }
                catch { /*ignore exceptions*/ }
            }

            // for stash and pop commands, check that target1 is a valid tag
            if ((args.Stash > 0 || args.Pop > 0) && !r_allowedExt.IsMatch(args.Target1))
            {
                await Context.Channel.SendMessageAsync($"**The supplied tag is not allowed (only a-z, 0-9)!**");

                return;
            }

            // check that the cluster key is valid
            ArkClusterContext clusterContext = args.ClusterKey != null?_contextManager.GetCluster(args.ClusterKey) : null;

            if (clusterContext == null)
            {
                await Context.Channel.SendMessageAsync($"**Cloud commands need to be prefixed with a valid cluster key.**");

                return;
            }

            // check that there are one or more servers in the cluster
            var serverContexts = _contextManager.GetServersInCluster(clusterContext.Config.Key);

            if (!(serverContexts?.Length > 0))
            {
                await Context.Channel.SendMessageAsync($"**There are no servers in the cluster.**");

                return;
            }

            /* ---------------------------------------------------------------
            *  List cloud save backups available for a given player.
            *  --------------------------------------------------------------- */
            if (args.List > 0)
            {
                var result = GetBackupFiles(clusterContext.Config, serverContexts.Select(x => x.Config.Key).ToArray(), args.List);

                if (result.Count > 0)
                {
                    var tbl = OutputCloudBackupListingTable(result, args.Skip);
                    sb.Append(tbl);
                }
                else
                {
                    sb.AppendLine("**Could not find any cloud save backups...**");
                }
            }

            /* ---------------------------------------------------------------
            *  Stash the current cloud save with a given tag to fetch at a later time.
            *  --------------------------------------------------------------- */
            else if (args.Stash > 0)
            {
                var result = _savegameBackupService.StashCloudSave(clusterContext.Config, args.Stash, args.Target1);
                if (result == StashResult.Successfull)
                {
                    sb.AppendLine($"**Cloud save stashed as '{args.Target1}'!**");
                }
                else if (result == StashResult.SourceMissing)
                {
                    sb.AppendLine("**There is no cloud save to stash...**");
                }
                else if (result == StashResult.TargetExists)
                {
                    sb.AppendLine("**The supplied tag is already being used...**");
                }
                else
                {
                    sb.AppendLine("**Failed to stash cloud save...**");
                }
            }

            /* ---------------------------------------------------------------
            *  Fetch a cloud save previously stashed with a given tag and set it as the current cloud save.
            *  --------------------------------------------------------------- */
            else if (args.Pop > 0)
            {
                var result = _savegameBackupService.PopCloudSave(clusterContext.Config, args.Pop, args.Target1);
                if (result == StashResult.Successfull)
                {
                    sb.AppendLine($"**Cloud save popped from '{args.Target1}'!**");
                }
                else if (result == StashResult.SourceMissing)
                {
                    sb.AppendLine("**The supplied tag does not exist...**");
                }
                else if (result == StashResult.TargetExists)
                {
                    sb.AppendLine("**A cloud save already exists, please delete/stash it before popping...**");
                }
                else
                {
                    sb.AppendLine("**Failed to pop cloud save...**");
                }
            }

            /* ---------------------------------------------------------------
            *  Delete the current cloud save for a given player.
            *  --------------------------------------------------------------- */
            else if (args.Delete > 0)
            {
                var targetPath = Path.Combine(clusterContext.Config.SavePath, $"{args.Delete}");
                if (File.Exists(targetPath))
                {
                    try
                    {
                        File.Delete(targetPath);
                        sb.AppendLine($"**Cloud save deleted!**");
                    }
                    catch
                    {
                        sb.AppendLine($"**Failed to delete cloud save...**");
                    }
                }
                else
                {
                    sb.AppendLine($"**There is no cloud save to delete...**");
                }
            }

            /* ---------------------------------------------------------------
            *  Create a backup of all cloud save files for a given player (including stashed, .tmpprofile etc.)
            *  --------------------------------------------------------------- */
            else if (args.Backup > 0)
            {
                var result = _savegameBackupService.CreateClusterBackupForSteamId(clusterContext.Config, args.Backup);
                if (result != null && result.ArchivePaths?.Length > 0)
                {
                    sb.AppendLine($"**Cloud save backup successfull!**");
                }
                else
                {
                    sb.AppendLine("**Failed to backup cloud save...**");
                }
            }

            /* ---------------------------------------------------------------
            *  Get detailed information for a single backup archive or cloud save file.
            *  --------------------------------------------------------------- */
            else if (args.Details > 0 && backupHash.HasValue)
            {
                var result = GetBackupFiles(clusterContext.Config, serverContexts.Select(x => x.Config.Key).ToArray(), args.Details, backupHash.Value)
                             .Find(x => x.Path.GetHashCode() == backupHash.Value);

                if (result == null)
                {
                    await Context.Channel.SendMessageAsync($"**Failed to find the given backup hash!**");

                    return;
                }

                var data = result.Files.Select(file =>
                {
                    string tmpFilePath = null;
                    ArkCloudInventory cloudInventory = null;
                    try
                    {
                        string filePath = null;
                        if (result is FromServerBackupListEntity)
                        {
                            filePath = result.FullPath;
                        }
                        else
                        {
                            filePath = tmpFilePath = FileHelper.ExtractFileInZipFile(result.FullPath, file);
                        }

                        var cresult    = ArkClusterData.LoadSingle(filePath, CancellationToken.None, true, true);
                        cloudInventory = cresult.Success ? cresult.Data : null;
                    }
                    catch
                    {
                        /*ignore exception*/
                    }
                    finally
                    {
                        if (tmpFilePath != null)
                        {
                            File.Delete(tmpFilePath);
                        }
                    }

                    return(new
                    {
                        FilePath = file,
                        CloudSaveHash = file.GetHashCode(),
                        DinoCount = cloudInventory?.Dinos?.Length,
                        CharactersCount = cloudInventory?.Characters?.Length,
                        ItemsCount = cloudInventory?.Items?.Length
                    });
                }).ToArray();

                var tableBackupFiles = FixedWidthTableHelper.ToString(data, x => x
                                                                      .For(y => y.FilePath, header: "Cloud Save")
                                                                      .For(y => y.CloudSaveHash, header: "Cloud Save Hash", alignment: 1, format: "X")
                                                                      .For(y => y.DinoCount, header: "Dinos", alignment: 1)
                                                                      .For(y => y.CharactersCount, header: "Characters", alignment: 1)
                                                                      .For(y => y.ItemsCount, header: "Items", alignment: 1));

                var tableBackupEntries = OutputCloudBackupListingTable(new[] { result }, 0, 1);

                sb.Append(tableBackupEntries);
                sb.Append($"```{tableBackupFiles}```");
            }

            /* ---------------------------------------------------------------
            *  Restore a single cloud save file from a backup archive or cloud save file (some overlap with the less verbose pop command).
            *  --------------------------------------------------------------- */
            else if (args.Restore > 0 && backupHash.HasValue && cloudSaveHash.HasValue)
            {
                var result = GetBackupFiles(clusterContext.Config, serverContexts.Select(x => x.Config.Key).ToArray(), args.Restore, backupHash.Value)
                             .Find(x => x.Path.GetHashCode() == backupHash.Value);

                if (result == null)
                {
                    await Context.Channel.SendMessageAsync($"**Failed to find the given backup hash!**");

                    return;
                }

                var cloudSaveFile = result.Files.FirstOrDefault(x => x.GetHashCode() == cloudSaveHash.Value);
                if (cloudSaveFile == null)
                {
                    await Context.Channel.SendMessageAsync($"**Failed to find the given cloud save hash!**");

                    return;
                }

                var targetPath = Path.Combine(clusterContext.Config.SavePath, $"{args.Restore}");
                if (File.Exists(targetPath))
                {
                    await Context.Channel.SendMessageAsync("**A cloud save already exists, please delete/stash it before restoring...**");

                    return;
                }

                string tmpFilePath = null;
                try
                {
                    string filePath = null;
                    if (result is FromServerBackupListEntity)
                    {
                        filePath = result.FullPath;
                    }
                    else
                    {
                        filePath = tmpFilePath = FileHelper.ExtractFileInZipFile(result.FullPath, cloudSaveFile);
                    }

                    File.Copy(filePath, targetPath);

                    sb.AppendLine($"**Cloud save successfully restored!**");
                }
                catch
                {
                    /*ignore exception*/
                    sb.AppendLine($"**Failed to restore cloud save...**");
                }
                finally
                {
                    if (tmpFilePath != null)
                    {
                        File.Delete(tmpFilePath);
                    }
                }
            }
            else
            {
                var syntaxHelp = MethodBase.GetCurrentMethod().GetCustomAttribute <SyntaxHelpAttribute>()?.SyntaxHelp;
                var name       = MethodBase.GetCurrentMethod().GetCustomAttribute <CommandAttribute>()?.Text;

                await Context.Channel.SendMessageAsync(string.Join(Environment.NewLine, new string[] {
                    $"**My logic circuits cannot process this command! I am just a bot after all... :(**",
                    !string.IsNullOrWhiteSpace(syntaxHelp) ? $"Help me by following this syntax: **!{name}** {syntaxHelp}" : null
                }.Where(x => x != null)));

                return;
            }

            var msg = sb.ToString();

            if (!string.IsNullOrWhiteSpace(msg))
            {
                await CommandHelper.SendPartitioned(Context.Channel, sb.ToString());
            }
        }