/// <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); } }