diff --git a/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM1.cs b/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM1.cs
index 1868e31122056795daab4579f741463ef95e7fed..919e7e6b7d9c3e62559ca51beca75bb8d8c72784 100644
--- a/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM1.cs
+++ b/C#.NET/source/Yitter.IdGenerator/Core/SnowWorkerM1.cs
@@ -5,27 +5,27 @@
* 版权说明:只要保留本版权,你可以免费使用、修改、分发本代码。
* 免责条款:任何因为本代码产生的系统、法律、政治、宗教问题,均与版权所有者无关。
*
- */
-
-using System;
-using System.Threading;
+ */
+
+using System;
+using System.Threading;
using System.Threading.Tasks;
-namespace Yitter.IdGenerator
-{
- ///
- /// 雪花漂移算法
- ///
- internal class SnowWorkerM1 : ISnowWorker
+namespace Yitter.IdGenerator
+{
+ ///
+ /// 雪花漂移算法
+ ///
+ internal class SnowWorkerM1 : ISnowWorker
{
///
/// 基础时间
///
- protected readonly DateTime BaseTime;
+ protected readonly DateTime BaseTime;
- ///
- /// 机器码
- ///
+ ///
+ /// 机器码
+ ///
protected readonly ushort WorkerId = 0;
///
@@ -40,7 +40,7 @@ namespace Yitter.IdGenerator
///
/// 最大序列数(含)
- ///
+ ///
protected readonly int MaxSeqNumber = 0;
///
@@ -57,11 +57,11 @@ namespace Yitter.IdGenerator
protected static object _SyncLock = new object();
protected ushort _CurrentSeqNumber;
- protected long _LastTimeTick = 0; // -1L
- protected long _TurnBackTimeTick = 0; // -1L;
- protected byte _TurnBackIndex = 0;
-
- protected bool _IsOverCost = false;
+ protected long _LastTimeTick = 0; // -1L
+ protected long _TurnBackTimeTick = 0; // -1L;
+ protected byte _TurnBackIndex = 0;
+
+ protected bool _IsOverCost = false;
protected int _OverCostCountInOneTerm = 0;
protected int _GenCountInOneTerm = 0;
protected int _TermIndex = 0;
@@ -71,8 +71,8 @@ namespace Yitter.IdGenerator
public Action GenAction { get; set; }
-
- public SnowWorkerM1(IdGeneratorOptions options)
+
+ public SnowWorkerM1(IdGeneratorOptions options)
{
// 1.BaseTime
if (options.BaseTime != DateTime.MinValue)
@@ -117,17 +117,17 @@ namespace Yitter.IdGenerator
MinSeqNumber = options.MinSeqNumber;
// 7.Others
- TopOverCostCount = options.TopOverCostCount;
+ TopOverCostCount = options.TopOverCostCount;
if (TopOverCostCount == 0)
{
TopOverCostCount = 2000;
}
- _TimestampShift = (byte)(WorkerIdBitLength + SeqBitLength);
- _CurrentSeqNumber = options.MinSeqNumber;
-
- //_BaseTimeTick = BaseTime.Ticks;
- //_StartTimeTick = (long)(DateTime.UtcNow.Subtract(BaseTime).TotalMilliseconds) - Environment.TickCount;
+ _TimestampShift = (byte)(WorkerIdBitLength + SeqBitLength);
+ _CurrentSeqNumber = options.MinSeqNumber;
+
+ //_BaseTimeTick = BaseTime.Ticks;
+ //_StartTimeTick = (long)(DateTime.UtcNow.Subtract(BaseTime).TotalMilliseconds) - Environment.TickCount;
}
@@ -137,7 +137,7 @@ namespace Yitter.IdGenerator
{
GenAction(arg);
});
- }
+ }
private void BeginOverCostAction(in long useTimeTick)
{
@@ -338,11 +338,11 @@ namespace Yitter.IdGenerator
return result;
}
- protected virtual long GetCurrentTimeTick()
- {
- //return (long)(DateTime.UtcNow - BaseTime).Ticks;
- //return (long)(_StartTimeTick + Environment.TickCount);
- return (long)(DateTime.UtcNow - BaseTime).TotalMilliseconds;
+ protected virtual long GetCurrentTimeTick()
+ {
+ //return (long)(DateTime.UtcNow - BaseTime).Ticks;
+ //return (long)(_StartTimeTick + Environment.TickCount);
+ return (long)(DateTime.UtcNow - BaseTime).TotalMilliseconds;
}
protected virtual long GetNextTimeTick()
@@ -364,6 +364,6 @@ namespace Yitter.IdGenerator
{
return _IsOverCost ? NextOverCostId() : NextNormalId();
}
- }
- }
-}
+ }
+ }
+}
diff --git a/Node.js/README.md b/Node.js/README.md
index 493a39b079c2b283f8d97f8675e366649864dbfb..f4a8991b016b83b23ad2c22c08c7d5a3aefd65c0 100644
--- a/Node.js/README.md
+++ b/Node.js/README.md
@@ -6,6 +6,12 @@
代码贡献者:bubao 布宝
+执行测试代码
+
+```bash
+node test/test2.js
+```
+
## 使用
```js
@@ -17,4 +23,6 @@ for (let index = 0; index < 5000; index++) {
}
```
+## 其他帮助
+在mysql中int类型最大长度是10位数字,由于本算法默认生成的是15位,最短也是11位,所以在mysql中需要使用bigint数据类型
diff --git a/Node.js/test/test2.js b/Node.js/test/test2.js
new file mode 100644
index 0000000000000000000000000000000000000000..1aa6048c0293a15740d8bd3eae96da3d8b972e06
--- /dev/null
+++ b/Node.js/test/test2.js
@@ -0,0 +1,20 @@
+const GenId = require('..')
+
+
+function test1() {
+ const genid = new GenId({ WorkerId: 1 })
+ for (let index = 0; index < 5000; index++) {
+ console.log(genid.NextId());
+ }
+}
+function test2() {
+ const genid = new GenId({ WorkerId: 1 })
+ const id = genid.NextId()
+ console.log(typeof (id))
+ console.log(id, id.toString().length)
+}
+
+function main() {
+ test2()
+}
+main()
\ No newline at end of file
diff --git a/TypeScript/.gitignore b/TypeScript/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..d8e9788f00196eaac012b7050a0b06f445dc7192
--- /dev/null
+++ b/TypeScript/.gitignore
@@ -0,0 +1,3 @@
+.vscode
+node_modules
+env.config.js
\ No newline at end of file
diff --git a/TypeScript/README.md b/TypeScript/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a30a043acd83f33a9989ff20dec434966bbf41c0
--- /dev/null
+++ b/TypeScript/README.md
@@ -0,0 +1,32 @@
+# ❄ idgenerator-TypeScript
+
+## 介绍
+
+项目更多介绍参照:https://github.com/yitter/idgenerator
+
+代码贡献者:zhupengfei 在 bubao 布宝 基础上改版而来,感谢bubao 布宝
+
+
+执行测试代码
+
+```bash
+ts-node test/test.ts
+
+NODE_ENV=development REDIS_HOST=127.0.0.1
+```
+
+
+
+## 使用
+
+```js
+import { Genid } from '../index'
+
+
+let gen = new Genid({ WorkerId: 1 })
+let id1 = gen.NextId()
+console.log(id1, id1.toString().length)
+
+```
+
+
diff --git a/TypeScript/package-lock.json b/TypeScript/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..46ffb48f4a610149b953fb04958b887eb5e22f47
--- /dev/null
+++ b/TypeScript/package-lock.json
@@ -0,0 +1,166 @@
+{
+ "name": "cherry-id",
+ "version": "0.0.3",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@cspotcode/source-map-consumer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.nlark.com/@cspotcode/source-map-consumer/download/@cspotcode/source-map-consumer-0.8.0.tgz",
+ "integrity": "sha1-M79LeznBeIIWBvZpu8RHpqYpeGs=",
+ "dev": true
+ },
+ "@cspotcode/source-map-support": {
+ "version": "0.6.1",
+ "resolved": "https://registry.nlark.com/@cspotcode/source-map-support/download/@cspotcode/source-map-support-0.6.1.tgz",
+ "integrity": "sha1-EYUR8xbi6H7kKUdhho4lTT2keWA=",
+ "dev": true,
+ "requires": {
+ "@cspotcode/source-map-consumer": "0.8.0"
+ }
+ },
+ "@tsconfig/node10": {
+ "version": "1.0.8",
+ "resolved": "https://registry.nlark.com/@tsconfig/node10/download/@tsconfig/node10-1.0.8.tgz?cache=0&sync_timestamp=1623230253873&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40tsconfig%2Fnode10%2Fdownload%2F%40tsconfig%2Fnode10-1.0.8.tgz",
+ "integrity": "sha1-weToDW+WT77LM1nEO9SLQPfK2tk=",
+ "dev": true
+ },
+ "@tsconfig/node12": {
+ "version": "1.0.9",
+ "resolved": "https://registry.nlark.com/@tsconfig/node12/download/@tsconfig/node12-1.0.9.tgz",
+ "integrity": "sha1-YsH23uLr2a6tgNw6+laBDljhoEw=",
+ "dev": true
+ },
+ "@tsconfig/node14": {
+ "version": "1.0.1",
+ "resolved": "https://registry.nlark.com/@tsconfig/node14/download/@tsconfig/node14-1.0.1.tgz?cache=0&sync_timestamp=1623230252928&other_urls=https%3A%2F%2Fregistry.nlark.com%2F%40tsconfig%2Fnode14%2Fdownload%2F%40tsconfig%2Fnode14-1.0.1.tgz",
+ "integrity": "sha1-lfLRZ/+5uNIGiwsjUwL6/U33EfI=",
+ "dev": true
+ },
+ "@tsconfig/node16": {
+ "version": "1.0.2",
+ "resolved": "https://registry.nlark.com/@tsconfig/node16/download/@tsconfig/node16-1.0.2.tgz",
+ "integrity": "sha1-Qjx3h30Fadsg4fyAiFrEEYMUAQ4=",
+ "dev": true
+ },
+ "@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.nlark.com/@types/json5/download/@types/json5-0.0.29.tgz",
+ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "16.7.6",
+ "resolved": "https://registry.nlark.com/@types/node/download/@types/node-16.7.6.tgz",
+ "integrity": "sha1-hmZHjbgJWqZuJbfkafPntT6ihV4=",
+ "dev": true
+ },
+ "acorn": {
+ "version": "8.4.1",
+ "resolved": "https://registry.nlark.com/acorn/download/acorn-8.4.1.tgz?cache=0&sync_timestamp=1624526907659&other_urls=https%3A%2F%2Fregistry.nlark.com%2Facorn%2Fdownload%2Facorn-8.4.1.tgz",
+ "integrity": "sha1-VsNiUfx8q8cJatwY8Fr+gUMhoow=",
+ "dev": true
+ },
+ "acorn-walk": {
+ "version": "8.1.1",
+ "resolved": "https://registry.nlark.com/acorn-walk/download/acorn-walk-8.1.1.tgz",
+ "integrity": "sha1-Pdq3+E5KfiMT9sQUxbfayF9OPrw=",
+ "dev": true
+ },
+ "arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.nlark.com/arg/download/arg-4.1.3.tgz",
+ "integrity": "sha1-Jp/HrVuOQstjyJbVZmAXJhwUQIk=",
+ "dev": true
+ },
+ "cd": {
+ "version": "0.3.3",
+ "resolved": "https://registry.nlark.com/cd/download/cd-0.3.3.tgz",
+ "integrity": "sha1-EI7LV7/5O5a5EVxUVzz+8wCO+U0=",
+ "dev": true
+ },
+ "create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npm.taobao.org/create-require/download/create-require-1.1.1.tgz",
+ "integrity": "sha1-wdfo8eX2z8n/ZfnNNS03NIdWwzM=",
+ "dev": true
+ },
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.nlark.com/diff/download/diff-4.0.2.tgz",
+ "integrity": "sha1-YPOuy4nV+uUgwRqhnvwruYKq3n0=",
+ "dev": true
+ },
+ "json5": {
+ "version": "1.0.1",
+ "resolved": "https://registry.nlark.com/json5/download/json5-1.0.1.tgz",
+ "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.0"
+ }
+ },
+ "make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npm.taobao.org/make-error/download/make-error-1.3.6.tgz",
+ "integrity": "sha1-LrLjfqm2fEiR9oShOUeZr0hM96I=",
+ "dev": true
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz?cache=0&sync_timestamp=1602337228360&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fminimist%2Fdownload%2Fminimist-1.2.5.tgz",
+ "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=",
+ "dev": true
+ },
+ "strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npm.taobao.org/strip-bom/download/strip-bom-3.0.0.tgz?cache=0&sync_timestamp=1618599642133&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-bom%2Fdownload%2Fstrip-bom-3.0.0.tgz",
+ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
+ "dev": true
+ },
+ "ts-node": {
+ "version": "10.2.1",
+ "resolved": "https://registry.nlark.com/ts-node/download/ts-node-10.2.1.tgz?cache=0&sync_timestamp=1629307498234&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fts-node%2Fdownload%2Fts-node-10.2.1.tgz",
+ "integrity": "sha1-TMk76gp6uiF5SX5luwjd/BmLOrU=",
+ "dev": true,
+ "requires": {
+ "@cspotcode/source-map-support": "0.6.1",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "yn": "3.1.1"
+ }
+ },
+ "tsconfig-paths": {
+ "version": "3.11.0",
+ "resolved": "https://registry.nlark.com/tsconfig-paths/download/tsconfig-paths-3.11.0.tgz?cache=0&sync_timestamp=1629839735580&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftsconfig-paths%2Fdownload%2Ftsconfig-paths-3.11.0.tgz",
+ "integrity": "sha1-lUwf6XPaYznHjgawPOLkiBC2XzY=",
+ "dev": true,
+ "requires": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.1",
+ "minimist": "^1.2.0",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "typescript": {
+ "version": "4.4.2",
+ "resolved": "https://registry.nlark.com/typescript/download/typescript-4.4.2.tgz?cache=0&sync_timestamp=1630011920137&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftypescript%2Fdownload%2Ftypescript-4.4.2.tgz",
+ "integrity": "sha1-bWGGQNQw41aaHftE99fmAM7T7oY=",
+ "dev": true
+ },
+ "yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.nlark.com/yn/download/yn-3.1.1.tgz?cache=0&sync_timestamp=1628974764210&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fyn%2Fdownload%2Fyn-3.1.1.tgz",
+ "integrity": "sha1-HodAGgnXZ8HV6rJqbkwYUYLS61A=",
+ "dev": true
+ }
+ }
+}
diff --git a/TypeScript/package.json b/TypeScript/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..010c9105f096bfc32b3c261e0469b4c17a2033b9
--- /dev/null
+++ b/TypeScript/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "cherry-id",
+ "version": "0.0.3",
+ "main": "index.ts",
+ "directories": {
+ "test": "test"
+ },
+ "scripts": {
+ "test": "ts-node ./test/test.ts"
+ },
+ "description": "",
+ "devDependencies": {
+ "@types/node": "^16.7.6",
+ "cd": "^0.3.3",
+ "ts-node": "^10.2.1",
+ "tsconfig-paths": "^3.11.0",
+ "typescript": "^4.4.2"
+ }
+}
diff --git a/TypeScript/snowflakeIdv1.ts b/TypeScript/snowflakeIdv1.ts
new file mode 100644
index 0000000000000000000000000000000000000000..eb1aff449a1d9a25122026faf1fb7e908c370c1d
--- /dev/null
+++ b/TypeScript/snowflakeIdv1.ts
@@ -0,0 +1,341 @@
+/**
+ *
+ */
+export class snowflakeIdv1 {
+
+ /**
+ * 雪花计算方法,(1-漂移算法|2-传统算法),默认 1
+ */
+ private Method
+
+ /**
+ * 基础时间(ms 单位),不能超过当前系统时间
+ */
+ private BaseTime
+
+ /**
+ * 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
+ */
+ private WorkerId
+
+ /**
+ * 机器码位长,默认值 6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过 22)
+ */
+ private WorkerIdBitLength
+
+ /**
+ * 序列数位长,默认值 6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过 22)
+ */
+ private SeqBitLength
+
+ /**
+ * 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值 0,表示最大序列数取最大值(2^SeqBitLength-1])
+ */
+ private MaxSeqNumber
+
+ /**
+ * 最小序列数(含),默认值 5,取值范围 [5, MaxSeqNumber],每毫秒的前 5 个序列数对应编号 0-4 是保留位,其中 1-4 是时间回拨相应预留位,0 是手工新值预留位
+ */
+ private MinSeqNumber
+
+ /**
+ * 最大漂移次数(含),默认 2000,推荐范围 500-10000(与计算能力有关)
+ */
+ private TopOverCostCount
+
+ /**
+ *
+ */
+ private _TimestampShift
+
+ /**
+ *
+ */
+ private _CurrentSeqNumber
+
+ /**
+ *
+ */
+ private _LastTimeTick: bigint
+
+ /**
+ * 回拨次序, 支持 4 次回拨次序(避免回拨重叠导致 ID 重复)
+ */
+ private _TurnBackTimeTick: bigint
+
+ /**
+ *
+ */
+ private _TurnBackIndex
+
+ /**
+ *
+ */
+ private _IsOverCost
+
+ /**
+ *
+ */
+ private _OverCostCountInOneTerm
+
+
+ /**
+ *Creates an instance of Genid.
+ * @author bubao
+ * @param {{
+ * Method: 1, // 雪花计算方法,(1-漂移算法|2-传统算法),默认 1
+ * BaseTime: 1577836800000, // 基础时间(ms 单位),不能超过当前系统时间
+ * WorkerId: Number, // 机器码,必须由外部设定,最大值 2^WorkerIdBitLength-1
+ * WorkerIdBitLength: 6, // 机器码位长,默认值 6,取值范围 [1, 15](要求:序列数位长+机器码位长不超过 22)
+ * SeqBitLength: 6, // 序列数位长,默认值 6,取值范围 [3, 21](要求:序列数位长+机器码位长不超过 22)
+ * MaxSeqNumber: 5, // 最大序列数(含),设置范围 [MinSeqNumber, 2^SeqBitLength-1],默认值 0,表示最大序列数取最大值(2^SeqBitLength-1])
+ * MinSeqNumber: 5, // 最小序列数(含),默认值 5,取值范围 [5, MaxSeqNumber],每毫秒的前 5 个序列数对应编号 0-4 是保留位,其中 1-4 是时间回拨相应预留位,0 是手工新值预留位
+ * TopOverCostCount: 2000// 最大漂移次数(含),默认 2000,推荐范围 500-10000(与计算能力有关)
+ * }} options
+ * @memberof Genid
+ */
+ constructor(options: any) {
+ if (options.WorkerId === undefined)
+ throw new Error("lost WorkerId")
+
+ // 1.BaseTime 2020年1月1日
+ const BaseTime = 1577836800000
+ if (!options.BaseTime || options.BaseTime < 0)
+ options.BaseTime = BaseTime
+
+ // 2.WorkerIdBitLength
+ const WorkerIdBitLength = 6
+ if (!options.WorkerIdBitLength || options.WorkerIdBitLength < 0)
+ options.WorkerIdBitLength = WorkerIdBitLength
+
+ // 4.SeqBitLength
+ const SeqBitLength = 6
+ if (!options.SeqBitLength || options.SeqBitLength < 0)
+ options.SeqBitLength = SeqBitLength
+
+ // 5.MaxSeqNumber
+ const MaxSeqNumber = (1 << SeqBitLength) - 1
+ if (options.MaxSeqNumber <= 0 || options.MaxSeqNumber === undefined) {
+ options.MaxSeqNumber = MaxSeqNumber
+ }
+ // 6.MinSeqNumber
+ const MinSeqNumber = 5
+ if (!options.MinSeqNumber || options.MinSeqNumber < 0)
+ options.MinSeqNumber = MinSeqNumber
+
+ // 7.Others
+ const topOverCostCount = 2000
+ if (!options.TopOverCostCount || options.TopOverCostCount < 0)
+ options.TopOverCostCount = topOverCostCount
+
+
+ if (options.Method !== 2)
+ options.Method = 1
+ else
+ options.Method = 2
+
+ this.Method = BigInt(options.Method)
+ this.BaseTime = BigInt(options.BaseTime)
+ this.WorkerId = BigInt(options.WorkerId)
+ this.WorkerIdBitLength = BigInt(options.WorkerIdBitLength)
+ this.SeqBitLength = BigInt(options.SeqBitLength)
+ this.MaxSeqNumber = BigInt(options.MaxSeqNumber)
+ this.MinSeqNumber = BigInt(options.MinSeqNumber)
+ this.TopOverCostCount = BigInt(options.TopOverCostCount)
+
+ const timestampShift = this.WorkerIdBitLength + this.SeqBitLength
+ const currentSeqNumber = this.MinSeqNumber
+
+ this._TimestampShift = timestampShift
+ this._CurrentSeqNumber = currentSeqNumber
+
+ this._LastTimeTick = BigInt(0)
+ this._TurnBackTimeTick = BigInt(0)
+ this._TurnBackIndex = 0
+ this._IsOverCost = false
+ this._OverCostCountInOneTerm = 0
+ }
+
+ /**
+ * 当前序列号超过最大范围,开始透支使用序号号的通知事件,,本项暂未实现
+ * @returns
+ */
+ private BeginOverCostAction(useTimeTick: any) {
+
+ }
+
+ /**
+ * 当前序列号超过最大范围,结束透支使用序号号的通知事件,,本项暂未实现
+ * @returns
+ */
+ private EndOverCostAction(useTimeTick: any) {
+ // if m1._TermIndex > 10000 {
+ // m1._TermIndex = 0
+ // }
+ }
+
+ /**
+ * 开始时间回拨通知,本项暂未实现
+ * @returns
+ */
+ private BeginTurnBackAction(useTimeTick: any) {
+
+ }
+
+ /**
+ * 结束时间回拨通知,本项暂未实现
+ * @returns
+ */
+ private EndTurnBackAction(useTimeTick: any) {
+
+ }
+
+ /**
+ * 雪花漂移算法
+ * @returns
+ */
+ private NextOverCostId(): bigint {
+ const currentTimeTick = this.GetCurrentTimeTick()
+ if (currentTimeTick > this._LastTimeTick) {
+ this.EndOverCostAction(currentTimeTick)
+ //当前时间大于上次时间,说明是时间是递增的,这是正常情况
+ this._LastTimeTick = currentTimeTick
+ this._CurrentSeqNumber = this.MinSeqNumber
+ this._IsOverCost = false
+ this._OverCostCountInOneTerm = 0
+ // this._GenCountInOneTerm = 0
+ return this.CalcId(this._LastTimeTick)
+ }
+ if (this._OverCostCountInOneTerm >= this.TopOverCostCount) {
+ //当前漂移次数超过最大限制
+
+ // TODO: 在漂移终止,等待时间对齐时,如果发生时间回拨较长,则此处可能等待较长时间。可优化为:在漂移终止时增加时间回拨应对逻辑。(该情况发生概率很低)
+
+ this.EndOverCostAction(currentTimeTick)
+ this._LastTimeTick = this.GetNextTimeTick()
+ this._CurrentSeqNumber = this.MinSeqNumber
+ this._IsOverCost = false
+ this._OverCostCountInOneTerm = 0
+ // this._GenCountInOneTerm = 0
+ return this.CalcId(this._LastTimeTick)
+ }
+ if (this._CurrentSeqNumber > this.MaxSeqNumber) {
+ //当前序列数超过最大限制,则要提前透支
+ this._LastTimeTick++
+ this._CurrentSeqNumber = this.MinSeqNumber
+ this._IsOverCost = true
+ this._OverCostCountInOneTerm++
+ // this._GenCountInOneTerm++
+
+ return this.CalcId(this._LastTimeTick)
+ }
+
+ // this._GenCountInOneTerm++
+ return this.CalcId(this._LastTimeTick)
+ }
+
+ /**
+ * 常规雪花算法
+ * @returns
+ */
+ private NextNormalId() {
+ const currentTimeTick = this.GetCurrentTimeTick()
+ if (currentTimeTick < this._LastTimeTick) {
+ if (this._TurnBackTimeTick < 1) {
+ this._TurnBackTimeTick = this._LastTimeTick - BigInt(1)
+ this._TurnBackIndex++
+ // 每毫秒序列数的前 5 位是预留位,0 用于手工新值,1-4 是时间回拨次序
+ // 支持 4 次回拨次序(避免回拨重叠导致 ID 重复),可无限次回拨(次序循环使用)。
+ if (this._TurnBackIndex > 4)
+ this._TurnBackIndex = 1
+
+ this.BeginTurnBackAction(this._TurnBackTimeTick)
+ }
+ return this.CalcTurnBackId(this._TurnBackTimeTick)
+ }
+ // 时间追平时,_TurnBackTimeTick 清零
+ if (this._TurnBackTimeTick > 0) {
+ this.EndTurnBackAction(this._TurnBackTimeTick)
+ this._TurnBackTimeTick = BigInt(0)
+ }
+
+ if (currentTimeTick > this._LastTimeTick) {
+ this._LastTimeTick = currentTimeTick
+ this._CurrentSeqNumber = this.MinSeqNumber
+ return this.CalcId(this._LastTimeTick)
+ }
+
+ if (this._CurrentSeqNumber > this.MaxSeqNumber) {
+ this.BeginOverCostAction(currentTimeTick)
+ // this._TermIndex++
+ this._LastTimeTick++
+ this._CurrentSeqNumber = this.MinSeqNumber
+ this._IsOverCost = true
+ this._OverCostCountInOneTerm = 1
+ // this._GenCountInOneTerm = 1
+
+ return this.CalcId(this._LastTimeTick)
+ }
+
+ return this.CalcId(this._LastTimeTick)
+ }
+
+ /**
+ * 生成ID
+ * @param useTimeTick 时间戳
+ * @returns
+ */
+ private CalcId(useTimeTick: bigint) {
+ //ID组成 1.相对基础时间的时间差 | 2.WorkerId | 3.序列数
+ //时间差,是生成ID时的系统时间减去 BaseTime 的总时间差(毫秒单位)
+ const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._CurrentSeqNumber)
+ this._CurrentSeqNumber++
+ return result
+ }
+
+ /**
+ * 生成时间回拨ID
+ * @returns
+ */
+ private CalcTurnBackId(useTimeTick: any) {
+ const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._TurnBackIndex)
+ this._TurnBackTimeTick--
+ return result
+ }
+
+ /**
+ *
+ * @returns
+ */
+ private GetCurrentTimeTick() {
+ const millis = BigInt((new Date()).valueOf())
+ return millis - this.BaseTime
+ }
+
+ /**
+ *
+ * @returns
+ */
+ private GetNextTimeTick() {
+ let tempTimeTicker = this.GetCurrentTimeTick()
+ while (tempTimeTicker <= this._LastTimeTick) {
+ tempTimeTicker = this.GetCurrentTimeTick()
+ }
+ return tempTimeTicker
+ }
+
+ /**
+ * 生成ID
+ * @returns
+ */
+ public NextId(): number {
+ if (this.Method == BigInt(1)) {
+ //雪花漂移算法
+ return parseInt(this.NextOverCostId().toString())
+ } else {
+ //常规雪花算法
+ return parseInt(this.NextNormalId().toString())
+ }
+ }
+}
+
diff --git a/TypeScript/test/test.ts b/TypeScript/test/test.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f41bd286a51cf71eaf39251fe8e9fb2c6a513d21
--- /dev/null
+++ b/TypeScript/test/test.ts
@@ -0,0 +1,33 @@
+import { snowflakeIdv1 } from '../snowflakeIdv1'
+
+const WorkerId = process.env.WorkerId == undefined ? 1 : process.env.WorkerId
+
+const Method = process.env.Method == undefined ? 1 : process.env.Method
+
+
+console.log("WorkerId:" + WorkerId)
+console.log("Method:" + Method)
+console.log("--------------------")
+let gen1 = new snowflakeIdv1({ WorkerId: WorkerId, Method: Method })
+
+
+
+function test1() {
+ let id1 = gen1.NextId()
+ console.log(id1, id1.toString().length)
+}
+
+function test2() {
+ let id1 = gen1.NextId()
+ console.log(typeof (id1))
+ console.log(id1, id1.toString().length)
+}
+
+function main() {
+ test2()
+}
+main()
+
+
+
+
diff --git a/TypeScript/tsconfig.json b/TypeScript/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..f1e6df9e9327114eca56fe9440c76db17f3caa14
--- /dev/null
+++ b/TypeScript/tsconfig.json
@@ -0,0 +1,76 @@
+{
+ "compilerOptions": {
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
+
+ /* Basic Options */
+ // "incremental": true, /* Enable incremental compilation */
+ "target": "ES2020",
+ /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
+ "module": "commonjs",
+ /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
+ // "lib": [], /* Specify library files to be included in the compilation. */
+ // "allowJs": true, /* Allow javascript files to be compiled. */
+ // "checkJs": true, /* Report errors in .js files. */
+ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
+ // "declaration": true, /* Generates corresponding '.d.ts' file. */
+ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
+ // "sourceMap": true, /* Generates corresponding '.map' file. */
+ // "outFile": "./", /* Concatenate and emit output to single file. */
+ // "outDir": "./", /* Redirect output structure to the directory. */
+ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
+ // "composite": true, /* Enable project compilation */
+ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
+ // "removeComments": true, /* Do not emit comments to output. */
+ // "noEmit": true, /* Do not emit outputs. */
+ // "importHelpers": true, /* Import emit helpers from 'tslib'. */
+ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
+ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
+
+ /* Strict Type-Checking Options */
+ "strict": true,
+ /* Enable all strict type-checking options. */
+ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
+ // "strictNullChecks": true, /* Enable strict null checks. */
+ // "strictFunctionTypes": true, /* Enable strict checking of function types. */
+ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
+ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
+ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
+ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
+
+ /* Additional Checks */
+ // "noUnusedLocals": true, /* Report errors on unused locals. */
+ // "noUnusedParameters": true, /* Report errors on unused parameters. */
+ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
+ // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
+ // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
+
+ /* Module Resolution Options */
+ // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
+ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
+ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
+ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
+ // "typeRoots": [], /* List of folders to include type definitions from. */
+ // "types": [], /* Type declaration files to be included in compilation. */
+ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+ "esModuleInterop": true,
+ /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
+
+ /* Source Map Options */
+ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
+ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
+ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
+
+ /* Experimental Options */
+ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
+ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
+
+ /* Advanced Options */
+ "skipLibCheck": true,
+ /* Skip type checking of declaration files. */
+ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
+ }
+}
\ No newline at end of file