コード例 #1
0
        /// <summary>
        /// Download a content patch file from a file store.  Currently, Azure
        /// file stores are assumed.  Both compressed and uncompressed versions
        /// of the file are tried in respective order.
        /// </summary>
        /// <param name="FileStorePath">Supplies the remote file name that
        /// designates the file to download.</param>
        /// <param name="LocalFileName">Supplies the local file name to
        /// download to.</param>
        /// <param name="ConnectionString">Supplies the file store connection
        /// string.</param>
        /// <param name="Script">Supplies the script object.</param>
        private static void DownloadContentPatchFromFileStore(string FileStorePath, string LocalFileName, string ConnectionString, ACR_ServerCommunicator Script)
        {
            if (String.IsNullOrEmpty(ConnectionString))
            {
                throw new NotSupportedException();
            }

            //
            // Initialize the file store provider.
            //

            FileStore          UpdaterStore     = FileStoreProvider.CreateAzureFileStore(ConnectionString);
            FileStoreContainer UpdaterContainer = UpdaterStore.GetContainerReference(FileStoreNamespace.ACRUpdater);
            FileStoreFile      UpdaterFile      = UpdaterContainer.GetFileReference(FileStorePath + ".gzip");

            //
            // First attempt to retrieve a gzip compressed version of the file
            // to patch.  If that fails then fall back to a plaintext version.
            //

            try
            {
                using (MemoryStream MemStream = new MemoryStream())
                {
                    UpdaterFile.Read(MemStream);

                    MemStream.Position = 0;

                    using (FileStream OutStream = File.Create(LocalFileName))
                    {
                        using (GZipStream CompressedStream = new GZipStream(MemStream, CompressionMode.Decompress))
                        {
                            CompressedStream.CopyTo(OutStream);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Script.WriteTimestampedLogEntry(String.Format("ModuleContentPatcher.DownloadContentPatchFromFileStore: Couldn't retrieve compressed file {0} from Azure, trying uncompressed file, due to exception: {1}",
                                                              FileStorePath,
                                                              e));

                UpdaterFile = UpdaterContainer.GetFileReference(FileStorePath);

                using (FileStream OutStream = File.Create(LocalFileName))
                {
                    UpdaterFile.Read(OutStream);
                }
            }
        }
コード例 #2
0
        /// <summary>
        /// Check if a file store file exists.
        /// </summary>
        /// <param name="FileStorePath">Supplies the remote file name that
        /// designates the file to check for existance.</param>
        /// <param name="ConnectionString">Supplies the file store connection
        /// string.</param>
        /// <returns>True if the file store file exists.</returns>
        private static bool ContentPatchFileStoreFileExists(string FileStorePath, string ConnectionString)
        {
            if (String.IsNullOrEmpty(ConnectionString))
            {
                return(false);
            }

            //
            // Initialize the file store provider.
            //

            FileStore          UpdaterStore     = FileStoreProvider.CreateAzureFileStore(ConnectionString);
            FileStoreContainer UpdaterContainer = UpdaterStore.GetContainerReference(FileStoreNamespace.ACRUpdater);
            FileStoreFile      UpdaterFile      = UpdaterContainer.GetFileReference(FileStorePath + ".gzip");

            try
            {
                if (UpdaterFile.Exists())
                {
                    return(true);
                }
            }
            catch
            {
            }

            UpdaterFile = UpdaterContainer.GetFileReference(FileStorePath);

            try
            {
                if (UpdaterFile.Exists())
                {
                    return(true);
                }
            }
            catch
            {
            }

            return(false);
        }
コード例 #3
0
        /// <summary>
        /// Synchronize a single character file from the spool directory to the
        /// remote storage provider.  The contents of the file to transfer are
        /// already in memory.
        ///
        /// This function is called from the transfer synchronization thread.
        /// </summary>
        /// <param name="AccountName">Supplies the account name.</param>
        /// <param name="CharacterFileName">Supplies the character file name,
        /// without path (e.g. character.bic).</param>
        /// <param name="Data">Supplies a pointer to the BIC memory
        /// image.</param>
        /// <param name="Length">Supplies the length, in bytes, of the BIC to
        /// transfer.</param>
        /// <param name="Context">Supplies a context handle.</param>
        /// <returns>TRUE on success.</returns>
        private static int OnSynchronizeAccountFileToVault(string AccountName, string CharacterFile, IntPtr Data, IntPtr Length, IntPtr Context)
        {
            try
            {
                //
                // Pass through to the default implementation if the connection
                // string is not defined in the database.
                //

                if (String.IsNullOrEmpty(StoreConnectionString))
                {
                    return(1);
                }

                try
                {
                    if (Length == IntPtr.Zero)
                    {
                        return(0);
                    }

                    //
                    // Canonicalize names to lowercase as the file store may be
                    // case sensitive and maintaining a mapping table in the
                    // database is problematic since the first save for a new
                    // account may be observed before the players record for
                    // that player is created (and a player could log in to two
                    // servers simultaneously and create orphaned records that
                    // way, or similarly during a database outage, etc.).
                    //
                    // The original filename is stored as metadata to keep local
                    // filesystems case preserving on servers.
                    //

                    string OriginalFileName = AccountName + "/" + CharacterFile;

                    AccountName   = AccountName.ToLowerInvariant();
                    CharacterFile = CharacterFile.ToLowerInvariant();

                    //
                    // Get the file store file for the character file and
                    // replace it with the new character file.
                    //

                    FileStoreDirectory StoreDirectory = Container.GetDirectoryReference(AccountName);
                    FileStoreFile      StoreFile      = StoreDirectory.GetFileReference(CharacterFile);

                    byte[] CharacterData = new byte[(int)Length];
                    Marshal.Copy(Data, CharacterData, 0, CharacterData.Length);

                    StoreFile.Metadata["OriginalFileName"] = OriginalFileName;
                    StoreFile.Write(new MemoryStream(CharacterData));

                    if (VerboseLoggingEnabled)
                    {
                        Logger.Log("ServerVaultConnector.OnSynchronizeAccountFileToVault: Uploaded vault file '{0}\\{1}'.",
                                   AccountName,
                                   CharacterFile);
                    }

                    return(1);
                }
                catch (Exception e)
                {
                    Logger.Log("ServerVaultConnector.OnSynchronizeAccountFileToVault('{0}', '{1}'): Exception: {2}",
                               AccountName,
                               CharacterFile,
                               e);

                    throw;
                }
            }
            catch
            {
                return(0);
            }
        }
コード例 #4
0
        static void Main(string[] args)
        {
            string ConnectionString = null;
            string DownloadTo       = null;
            string UploadFrom       = null;
            string DeleteFileName   = null;
            bool   IncludeAllFiles  = false;

            Console.CancelKeyPress += Console_CancelKeyPress;

            Console.WriteLine("ALFA Azure Vault Management Tool v{0}", Assembly.GetExecutingAssembly().GetName().Version);
            Console.WriteLine();

            for (int i = 0; i < args.Length; i += 1)
            {
                if (i + 1 < args.Length && args[i].ToLowerInvariant() == "-connectionstring")
                {
                    ConnectionString = args[i + 1];
                    i += 1;
                    continue;
                }
                else if (i + 1 < args.Length && args[i].ToLowerInvariant() == "-download")
                {
                    DownloadTo = args[i + 1];
                    i         += 1;
                    continue;
                }
                else if (i + 1 < args.Length && args[i].ToLowerInvariant() == "-upload")
                {
                    UploadFrom = args[i + 1];
                    i         += 1;
                    continue;
                }
                else if (i + 1 < args.Length && args[i].ToLowerInvariant() == "-delete")
                {
                    DeleteFileName = args[i + 1];
                    i += 1;
                    continue;
                }
                else if (args[i].ToLowerInvariant() == "-all")
                {
                    IncludeAllFiles = true;
                    continue;
                }

                Console.WriteLine("Unrecognized argument: {0}", args[i]);
                PrintUsage();
                return;
            }

            if ((String.IsNullOrEmpty(ConnectionString)) ||
                ((String.IsNullOrEmpty(DownloadTo) ? 0 : 1) + (String.IsNullOrEmpty(UploadFrom) ? 0 : 1) + (String.IsNullOrEmpty(DeleteFileName) ? 0 : 1) != 1))
            {
                PrintUsage();
                return;
            }

            try
            {
                FileStore          Store     = FileStoreProvider.CreateAzureFileStore(ConnectionString);
                FileStoreContainer Container = Store.GetContainerReference(FileStoreNamespace.ServerVault);

                if (!String.IsNullOrEmpty(DownloadTo))
                {
                    Console.WriteLine("Downloading from vault to {0} in (CTRL+C in 5 seconds to cancel)...", DownloadTo);
                    Thread.Sleep(5000);

                    foreach (FileStoreDirectory Directory in Container.GetDirectories())
                    {
                        foreach (FileStoreFile File in Directory.GetFiles())
                        {
                            string RemoteName;

                            if (AbortProgram)
                            {
                                Console.WriteLine("Cancelled.");
                                return;
                            }

                            //
                            // Attempt to create the local file using the
                            // original filename case.
                            //

                            File.FetchAttributes();
                            if (File.Metadata.TryGetValue("OriginalFileName", out RemoteName))
                            {
                                if (RemoteName.ToLowerInvariant() != File.Name)
                                {
                                    Console.WriteLine("* File {0} OriginalFileName {1} is malformed, ignoring.", File.Name, RemoteName);
                                    RemoteName = File.Name;
                                }
                            }
                            else
                            {
                                RemoteName = File.Name;
                            }

                            string RemoteDirName  = Path.GetDirectoryName(RemoteName);
                            string RemoteFileName = Path.GetFileName(RemoteName);

                            if (!IncludeAllFiles && !RemoteFileName.ToLowerInvariant().EndsWith(".bic"))
                            {
                                Console.WriteLine("* File {0} is not a character file, skipping...", RemoteName);
                                continue;
                            }

                            if (!ALFA.SystemInfo.IsSafeFileName(RemoteFileName) || RemoteDirName.IndexOfAny(Path.GetInvalidPathChars()) != -1)
                            {
                                Console.WriteLine("* File {0} has an unsafe filename, skipping...", RemoteName);
                                continue;
                            }

                            string         FileName = String.Format("{0}{1}{2}", DownloadTo, Path.DirectorySeparatorChar, RemoteDirName);
                            FileStream     FsFile   = null;
                            DateTimeOffset?Offset   = null;

                            if (!System.IO.Directory.Exists(FileName))
                            {
                                System.IO.Directory.CreateDirectory(FileName);
                            }

                            FileName = String.Format("{0}{1}{2}", FileName, Path.DirectorySeparatorChar, RemoteFileName);

                            //
                            // Download the file if it didn't exist locally, or
                            // if the local file was older than the vault based
                            // file.
                            //

                            try
                            {
                                try
                                {
                                    FsFile = System.IO.File.Open(FileName, FileMode.Open, FileAccess.ReadWrite);
                                    Offset = System.IO.File.GetLastWriteTimeUtc(FileName);
                                }
                                catch (DirectoryNotFoundException)
                                {
                                }
                                catch (FileNotFoundException)
                                {
                                }

                                if (FsFile == null)
                                {
                                    FsFile = System.IO.File.Open(FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                                    Offset = null;
                                }

                                if (Offset != null)
                                {
                                    Console.Write("Downloading file {0}...", FileName);

                                    try
                                    {
                                        try
                                        {
                                            File.ReadIfModifiedSince(FsFile, Offset.Value);
                                        }
                                        catch
                                        {
                                            FsFile.Dispose();
                                            System.IO.File.SetLastWriteTimeUtc(FileName, Offset.Value.UtcDateTime);
                                            throw;
                                        }

                                        FsFile.Dispose();
                                        System.IO.File.SetLastWriteTimeUtc(FileName, File.LastModified.Value.UtcDateTime);
                                        Console.WriteLine(" done.");
                                    }
                                    catch (FileStoreConditionNotMetException)
                                    {
                                        Console.WriteLine(" already up to date.");
                                    }
                                }
                                else
                                {
                                    Console.Write("Downloading file {0}...", FileName);

                                    try
                                    {
                                        File.Read(FsFile);
                                    }
                                    catch
                                    {
                                        FsFile.Dispose();
                                        System.IO.File.Delete(FileName);
                                    }

                                    FsFile.Dispose();
                                    System.IO.File.SetLastWriteTimeUtc(FileName, File.LastModified.Value.UtcDateTime);
                                    Console.WriteLine("done.");
                                }
                            }
                            finally
                            {
                                FsFile.Dispose();
                            }
                        }
                    }
                }
                else if (!String.IsNullOrEmpty(UploadFrom))
                {
                    Console.WriteLine("Uploading from {0} to vault (CTRL+C in 5 seconds to cancel)...", UploadFrom);
                    Thread.Sleep(5000);

                    Container.CreateIfNotExists();

                    //
                    // Canonicalize the upload from base path so that relative
                    // filenames can be ascertained for naming files that are
                    // transferred to the vault.
                    //

                    UploadFrom = Path.GetFullPath(UploadFrom);

                    if (UploadFrom.EndsWith(Path.DirectorySeparatorChar.ToString()))
                    {
                        UploadFrom = UploadFrom.Substring(0, UploadFrom.Length - 1);
                    }

                    foreach (string FsFileName in Directory.EnumerateFiles(UploadFrom, "*.bic", SearchOption.AllDirectories))
                    {
                        string RemoteName;

                        if (AbortProgram)
                        {
                            Console.WriteLine("Cancelled.");
                            return;
                        }

                        if (!IncludeAllFiles && !FsFileName.ToLowerInvariant().EndsWith(".bic"))
                        {
                            Console.WriteLine("* File {0} is not a character file, skipping...", FsFileName);
                            continue;
                        }

                        //
                        // Upload files that did not exist or which were newer
                        // on the local side.
                        //

                        RemoteName = FsFileName.Substring(UploadFrom.Length + 1);

                        DateTimeOffset FsLastModified = System.IO.File.GetLastWriteTimeUtc(FsFileName);

                        using (FileStream FsFile = System.IO.File.OpenRead(FsFileName))
                        {
                            Console.Write("Uploading file {0}...", RemoteName);

                            try
                            {
                                FileStoreFile RemoteFile = Container.GetFileReference(RemoteName.Replace('\\', '/').ToLowerInvariant());

                                try
                                {
                                    RemoteFile.FetchAttributes();

                                    if (RemoteFile.LastModified >= FsLastModified)
                                    {
                                        Console.WriteLine(" already up to date.");
                                        continue;
                                    }
                                }
                                catch
                                {
                                }

                                RemoteFile.Metadata["OriginalFileName"] = RemoteName.Replace('\\', '/');
                                RemoteFile.WriteIfNotModifiedSince(FsFile, FsLastModified);
                                Console.WriteLine(" done.");
                            }
                            catch (FileStoreConditionNotMetException)
                            {
                                Console.WriteLine(" already up to date.");
                            }
                        }
                    }
                }
                else if (!String.IsNullOrEmpty(DeleteFileName))
                {
                    Console.Write("Deleting file {0} from vault (CTRL+C in 5 seconds to cancel)...", DeleteFileName);
                    Thread.Sleep(5000);

                    if (AbortProgram)
                    {
                        Console.WriteLine("Cancelled.");
                        return;
                    }

                    //
                    // Delete vault file if it existed.
                    //

                    FileStoreFile RemoteFile = Container.GetFileReference(DeleteFileName.Replace('\\', '/').ToLowerInvariant());

                    if (!RemoteFile.Exists())
                    {
                        Console.Write(" file not found on the vault.");
                    }
                    else
                    {
                        RemoteFile.Delete();
                        Console.Write(" done");
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: {0}", e);
                return;
            }
        }
コード例 #5
0
        /// <summary>
        /// This thread function measures vault latency every
        /// VAULT_MEASUREMENT_INTERVAL milliseconds.
        ///
        /// Note that, because this function does not execute from a script
        /// context, it cannot call script functions.  Instead, a companion
        /// DelayCommand continuation on the main server thread will check the
        /// current latency value and save it as appropriate.
        /// </summary>
        private static void VaultPingThreadRoutine()
        {
            string VaultPingFile = String.Format(
                "{0}Server{1}.txt",
                SystemInfo.GetCentralVaultPath(),
                LocalServerId);

            for (; ;)
            {
                //
                // Open the ping file on the vault.  If we fail to open it then
                // something has gone wrong with the vault connection.
                //

                try
                {
                    string ConnectionString = FileStoreProvider.DefaultVaultConnectionString;

                    uint Tick = (uint)Environment.TickCount;

                    using (StreamWriter PingFile = File.CreateText(VaultPingFile))
                    {
                        PingFile.WriteLine(
                            "Server {0} is up at {1}.",
                            LocalServerId,
                            DateTime.UtcNow);
                    }

                    if (!String.IsNullOrEmpty(ConnectionString))
                    {
                        FileStore          Store          = FileStoreProvider.CreateAzureFileStore(ConnectionString);
                        FileStoreContainer StoreContainer = Store.GetContainerReference(FileStoreNamespace.ServerVault);
                        FileStoreFile      StoreFile      = StoreContainer.GetFileReference(String.Format("Server{0}.txt", LocalServerId));

                        using (MemoryStream MemStream = new MemoryStream())
                        {
                            StoreFile.Write(MemStream);
                        }
                    }

                    Tick = (uint)Environment.TickCount - Tick;

                    //
                    // Report the response time.
                    //

                    lock (CurrentLatencyLock)
                    {
                        CurrentVaultLatency = (int)Tick;
                    }
                }
                catch (Exception e)
                {
                    Logger.Log("LatencyMonitor.VaultPingThreadRoutine: Exception pinging server vault: {0}", e);

                    //
                    // Report a response time of -1 to indicate that no
                    // measurement could be taken.
                    //

                    lock (CurrentLatencyLock)
                    {
                        CurrentVaultLatency = (int)-1;
                    }
                }

                Thread.Sleep(VAULT_MEASUREMENT_INTERVAL);
            }
        }