示例#1
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);
            }
        }
        /// <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);
            }
        }