/// <summary> /// Get a Base36 encoded timestamp string, based on Epoch. Use for disposable /// strings where global/universal uniqueness is not critical. If using the /// default resolution of Microseconds, 5 character values are exhausted in 1 minute. /// 6 characters = ½ hour. 7 characters = 21 hours. 8 characters = 1 month. /// 9 characters = 3 years. 10 characters = 115 years. 11 characters = 4170 years. /// 12 characteres = 150 thousand years. /// </summary> /// <param name="length"></param> /// <param name="resolution"></param> /// <param name="sinceUtc">Defaults to Epoch</param> /// <param name="strict">If false (default), overflow values will use the /// value modulus 36. Otherwise it will throw an overflow exception.</param> /// <returns></returns> public string GetTimestamp(int length, TimestampResolution resolution = TimestampResolution.Microsecond, DateTime?sinceUtc = null, bool strict = false) { if (length < 1 || length > 12) { throw new ArgumentOutOfRangeException(nameof(length), "Length must be between 1 and 12; 36^13 overflows Int64.MaxValue"); } var origin = sinceUtc ?? _epoch; var elapsed = DateTime.UtcNow.Subtract(origin); long intervals; switch (resolution) { case TimestampResolution.Day: intervals = elapsed.Days; break; case TimestampResolution.Hour: intervals = Convert.ToInt64(elapsed.TotalHours); break; case TimestampResolution.Minute: intervals = Convert.ToInt64(elapsed.TotalMinutes); break; case TimestampResolution.Second: intervals = Convert.ToInt64(elapsed.TotalSeconds); break; case TimestampResolution.Millisecond: intervals = Convert.ToInt64(elapsed.TotalMilliseconds); break; case TimestampResolution.Microsecond: intervals = (long)(elapsed.TotalMilliseconds * 1000.0); // elapsed.TotalMicroseconds(); break; case TimestampResolution.Ticks: intervals = elapsed.Ticks; break; case TimestampResolution.None: default: throw new ArgumentOutOfRangeException(nameof(resolution)); } var combinations = Math.Pow(36, length); if (combinations < intervals) { if (strict) { throw new OverflowException(string.Format("At resolution {0}, value is greater than {1}-character timestamps can express.", resolution.ToString(), length)); } intervals = intervals % 36; } string encoded = Base36Converter.FromLong(intervals); return(encoded.Length > length? encoded.Substring(0, length) : encoded.PadLeft(length, '0')); }
/// <summary> /// Base36 representation of the SHA1 of the hostname. The constructor argument /// numServerCharacters controls the maximum length of this hash. /// </summary> /// <returns>2 character Base36 checksum of MD5 of hostname</returns> public string ComputeHostHash() { string hostname = Dns.GetHostName(); if (!hostname.HasValue()) { hostname = Environment.MachineName; } string hashHex; using (var sha1 = new SHA1Managed()) { hashHex = BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(hostname))); if (hashHex.Length > 14) // > 14 chars overflows int64 { hashHex = hashHex.Truncate(14); } } string hashBase36 = Base36Converter.FromHex(hashHex); if (hashBase36.Length > this._numServerCharacters) { hashBase36 = hashBase36.Truncate(this._numServerCharacters); } return(hashBase36); }
public void EncodeTest() { Assert.Equal("0", Base36Converter.Encode(0)); Assert.Equal("6TY", Base36Converter.Encode(8854)); Assert.Equal("AQF8AA0006EH", 1412823931503067241.ToBase36()); }
public void DecodeTest() { Assert.Equal(0, Base36Converter.Decode("")); Assert.Equal(0, Base36Converter.Decode("0")); Assert.Equal(-1, Base36Converter.Decode("%")); Assert.Equal(1412823931503067241, Base36Converter.Decode("AQF8AA0006EH")); }
/// <summary> /// Base36 representation of the SHA1 of the hostname. The constructor argument /// numServerCharacters controls the maximum length of this hash. /// </summary> /// <returns>2 character Base36 checksum of MD5 of hostname</returns> public string ComputeHostHash(string hostname = null) { if (_hostHashBase36?.Length == _numServerCharacters) { return(_hostHashBase36); } if (string.IsNullOrWhiteSpace(hostname)) { hostname = Dns.GetHostName() ?? Environment.MachineName; } string hashHex; using (var sha1 = System.Security.Cryptography.SHA1.Create()) { hashHex = BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(hostname))); if (hashHex.Length > 14) // > 14 chars overflows int64 { hashHex = hashHex.Substring(0, 14); } } string hashBase36 = Base36Converter.FromHex(hashHex); return(_hostHashBase36 = hashBase36); }
/// <summary> /// This is not cross-process safe. /// </summary> /// <returns></returns> private string GetRandomDigitsLock() { // NOTE: Using a mutex would enable cross-process locking. lock (_randomLock) { long next = _rnd.NextLong(this._maxRandom); return(Base36Converter.Encode(next)); } }
public void Next_Base36_Decode_Test() { var snowflakeIdWorker = new SnowflakeIdWorker(1, 1); var nextId = snowflakeIdWorker.NextId(); var encode = Base36Converter.Encode(nextId); var decode = Base36Converter.Decode(encode); Console.WriteLine(encode); Assert.AreEqual(nextId, decode); }
private string GetRandomBase36DigitsSafe() { lock (_randomLock) { long number = ConcurrentRandom.Random.NextLong(this._maxRandom); string encoded = Base36Converter.FromLong(number); return (encoded.Length == this._numRandomCharacters ? encoded : encoded.Length > this._numRandomCharacters ? encoded.Substring(0, _numRandomCharacters) : encoded.PadLeft(this._numRandomCharacters, '0')); } }
/// <summary> /// Gets random component of Id, pre trimmed and padded to the correct length. /// </summary> /// <returns></returns> private string GetRandomBase36DigitsSafe() { lock (_randomLock) { byte[] buffer = new byte[8]; _random.NextBytes(buffer); var number = Math.Abs(BitConverter.ToInt64(buffer, 0) % this._maxRandom); string encoded = Base36Converter.FromLong(number); return (encoded.Length == this._numRandomCharacters ? encoded : encoded.Length > this._numRandomCharacters ? encoded.Substring(0, _numRandomCharacters) : encoded.PadLeft(this._numRandomCharacters, '0')); } }
/// <summary> /// Gets a random Base36 string of the specified <paramref name="length"/>. /// </summary> /// <returns></returns> public string GetRandomString(int length) { if (length < 1 || length > 12) { throw new ArgumentOutOfRangeException("length", "Length must be between 1 and 12; 36^13 overflows Int64.MaxValue"); } lock (_randomLock) { var maxRandom = (long)Math.Pow(36, length); long random = ConcurrentRandom.Random.NextLong(maxRandom); string encoded = Base36Converter.FromLong(random); return(encoded.Length > length? encoded.Truncate(length) : encoded.PadLeft(length, '0')); } }
/// <summary> /// Gets a random Base36 string of the specified <paramref name="length"/>. /// </summary> /// <returns></returns> public string GetRandomString(int length) { if (length < 1 || length > 12) { throw new ArgumentOutOfRangeException(nameof(length), "Length must be between 1 and 12; 36^13 overflows Int64.MaxValue"); } lock (_randomLock) { var maxRandom = (long)Math.Pow(36, length); _random.NextBytes(_randomBuffer); var random = Math.Abs(BitConverter.ToInt64(_randomBuffer, 0) % maxRandom); string encoded = Base36Converter.FromLong(random); return(encoded.Length > length? encoded.Substring(0, length) : encoded.PadLeft(length, '0')); } }
/// <summary> /// Gets random component of Id, pre trimmed and padded to the correct length. /// </summary> /// <returns></returns> private string GetRandomBase36DigitsSafe() { if (_randomMutex.WaitOne()) { long random = _rnd.NextLong(this._maxRandom); string encoded = Base36Converter.FromInt64(random); try { return(encoded.Length > this._numRandomCharacters ? encoded.Truncate(this._numRandomCharacters) : encoded.PadLeft(this._numRandomCharacters, '0')); } finally { _randomMutex.ReleaseMutex(); } } throw new AbandonedMutexException(); }
/// <summary> /// Generates a unique, sequential, Base36 string; you control the len /// The first 10 characters are the microseconds elapsed since the InService DateTime /// (constant field you hardcode in this file). /// The next 2 characters are a compressed checksum of the MD5 of this host. /// The next 1 character is a reserved constant of 36 ('Z' in Base36). /// The last 3 characters are random number less than 46655 additional for additional uniqueness. /// </summary> /// <returns>Returns a unique, sequential, 16-character Base36 string</returns> public string NewId(bool delimited) { // Keep access sequential so threads cannot accidentally // read another thread's values within this method: // Microseconds since InService (using Stopwatch) provides the // first n chars (n = _numTimestampCharacters): lock (_sb) { _sb.Clear(); long microseconds = ConcurrentStopwatch.GetMicroseconds(); string base36Microseconds = Base36Converter.FromLong(microseconds); if (base36Microseconds.Length > this._numTimestampCharacters) { base36Microseconds = base36Microseconds.Substring(0, this._numTimestampCharacters); } _sb.Append(base36Microseconds.PadLeft(this._numTimestampCharacters, '0')); if (_numServerCharacters > 0) { _sb.Append(_hostHash.Substring(0, _numServerCharacters)); } if (!string.IsNullOrWhiteSpace(this._reservedValue)) { _sb.Append(this._reservedValue); } // Add the random component: _sb.Append(GetRandomBase36DigitsSafe()); if (!delimited || string.IsNullOrWhiteSpace(_delimiter) || this._delimiterPositions == null) { return(_sb.ToString()); } foreach (var pos in this._delimiterPositions) { _sb.Insert(pos, this._delimiter); } return(_sb.ToString()); } }
private async void timer1_Tick(object sender, EventArgs e) { var entity = helper.getPlurks(); PlurkContent = "" + entity.plurks[0].content; PlurkQualifier = "" + (entity.plurks[0].qualifier_translated != null ? entity.plurks[0].qualifier_translated : entity.plurks[0].qualifier); PlurkContent_raw = "" + entity.plurks[0].content_raw; PlurkName = entity.plurk_users.First().Value.display_name; PlurkUserID = entity.plurk_users.First().Key; PlurkID = entity.plurks[0].plurk_id; PlurkUserPURL = helper.getPublicProfile(PlurkUserID).user_info.avatar_big; plurkbase36 = (int)entity.plurks[0].plurk_id; string SRC = Base36Converter.ConvertTo(plurkbase36).ToLower(); char[] ArraySRC = SRC.ToCharArray(); Array.Reverse(ArraySRC); SRC = new string(ArraySRC); PlurkURL = "https://www.plurk.com/p/" + SRC; if (PlurkContent.Contains("<img src=")) { int temp = PlurkContent.IndexOf("<img src=") + 10; string strtemp = PlurkContent.Remove(0, temp); Url = strtemp.Substring(0, strtemp.IndexOf(textBox1.Text)); if (Url.Contains("https://images.plurk.com/mx_")) { Url = Url.Remove(Url.IndexOf("mx_"), 3); } } else { Url = ""; } if (PlurkUserPURL != PUPURL) { PUPURL = PlurkUserPURL; await SendMessage(); } }
public void TestSNPIDConversionToBase36() { // Berlin Orchestra Inspire var berlinInspire1 = Base36Converter.Encode(BERLIN_INSPIRE_1 - SNPID_CONST); Assert.Equal(BERLIN_INSPIRE_1_SNPID, berlinInspire1); // Berlin Orchestra Inspire 2 var berlinInspire2 = Base36Converter.Encode(BERLIN_INSPIRE_2 - SNPID_CONST); Assert.Equal(BERLIN_INSPIRE_2_SNPID, berlinInspire2); // Metropolis Ark 3 var metropolisArk3 = Base36Converter.Encode(METROPOLIS_ARK_3 - SNPID_CONST); Assert.Equal(METROPOLIS_ARK_3_SNPID, metropolisArk3); // Artist Series - Randys Prepared Piano var randysPreparedPiano = Base36Converter.Encode(RANDYS_PREPARED_PIANO - SNPID_CONST); Assert.Equal(RANDYS_PREPARED_PIANO_SNPID, randysPreparedPiano); }
/// <summary> /// Generates a unique, sequential, Base36 string; you control the len /// The first 10 characters are the microseconds elapsed since the InService DateTime /// (constant field you hardcode in this file). /// The next 2 characters are a compressed checksum of the MD5 of this host. /// The next 1 character is a reserved constant of 36 ('Z' in Base36). /// The last 3 characters are random number less than 46655 additional for additional uniqueness. /// </summary> /// <returns>Returns a unique, sequential, 16-character Base36 string</returns> public string NewId(bool delimited) { // Keep access sequential so threads cannot accidentally // read another thread's values within this method: var sb = new StringBuilder(); // Microseconds since InService (using Stopwatch) provides the // first n chars (n = _numTimestampCharacters): lock (sb) { long microseconds = GetMicrosecondsSafe(); string base36Microseconds = Base36Converter.FromLong(microseconds); if (base36Microseconds.Length > this._numTimestampCharacters) { base36Microseconds = base36Microseconds.Truncate(this._numTimestampCharacters); } sb.Append(base36Microseconds.PadLeft(this._numTimestampCharacters, '0')); sb.Append(_hostHash); if (this._reservedValue.HasValue()) { sb.Append(this._reservedValue); sb.Length += this._reservedValue.Length; // Truncates } // Add the random component: sb.Append(GetRandomBase36DigitsSafe()); if (!delimited || !this._delimiter.HasValue() || !this._delimiterPositions.HasContents()) { return(sb.ToString()); } foreach (var pos in this._delimiterPositions) { sb.Insert(pos, this._delimiter); } return(sb.ToString()); } }
/// <summary> /// Returns a random Base36 number 3 characters long. /// </summary> /// <returns></returns> private string GetRandomDigitsSpinLock() { long value; while (true) { bool lockTaken = false; try { _locker.Enter(ref lockTaken); value = _rnd.NextLong(this._maxRandom); break; } finally { if (lockTaken) { _locker.Exit(false); } } } return(Base36Converter.Encode(value)); }