This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 1a20e5378 feat: add 'range_id' algorithm for 'request-id' plugin 
(#8790)
1a20e5378 is described below

commit 1a20e5378fc344c66ee61ce50ce5d118c8773fad
Author: Tristan <[email protected]>
AuthorDate: Wed Feb 22 10:40:12 2023 +0800

    feat: add 'range_id' algorithm for 'request-id' plugin (#8790)
---
 apisix/plugins/request-id.lua        |  46 ++++++++-
 docs/en/latest/plugins/request-id.md |   4 +-
 docs/zh/latest/plugins/request-id.md |   4 +-
 t/plugin/request-id2.t               | 182 +++++++++++++++++++++++++++++++++++
 4 files changed, 229 insertions(+), 7 deletions(-)

diff --git a/apisix/plugins/request-id.lua b/apisix/plugins/request-id.lua
index ceddcdf94..3a7e6bc39 100644
--- a/apisix/plugins/request-id.lua
+++ b/apisix/plugins/request-id.lua
@@ -27,6 +27,9 @@ local tostring = tostring
 local math_pow = math.pow
 local math_ceil = math.ceil
 local math_floor = math.floor
+local math_random = math.random
+local str_byte = string.byte
+local ffi = require "ffi"
 
 local plugin_name = "request-id"
 
@@ -40,7 +43,27 @@ local schema = {
     properties = {
         header_name = {type = "string", default = "X-Request-Id"},
         include_in_response = {type = "boolean", default = true},
-        algorithm = {type = "string", enum = {"uuid", "snowflake", "nanoid"}, 
default = "uuid"}
+        algorithm = {
+            type = "string",
+            enum = {"uuid", "snowflake", "nanoid", "range_id"},
+            default = "uuid"
+        },
+        range_id = {
+            type = "object",
+            properties = {
+                length = {
+                    type = "integer",
+                    minimum = 6,
+                    default = 16
+                },
+                char_set = {
+                    type = "string",
+                    -- The Length is set to 6 just avoid too short length, it 
may repeat
+                    minLength = 6,
+                    default = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789"
+                }
+            }
+        }
     }
 }
 
@@ -202,14 +225,27 @@ local function next_id()
     return snowflake:next_id()
 end
 
+-- generate range_id
+local function get_range_id(range_id)
+    local res = ffi.new("unsigned char[?]", range_id.length)
+    for i = 0, range_id.length - 1 do
+        res[i] = str_byte(range_id.char_set, math_random(#range_id.char_set))
+    end
+    return ffi.string(res, range_id.length)
+end
 
-local function get_request_id(algorithm)
-    if algorithm == "uuid" then
+local function get_request_id(conf)
+    if conf.algorithm == "uuid" then
         return uuid()
     end
-    if algorithm == "nanoid" then
+    if conf.algorithm == "nanoid" then
         return nanoid.safe_simple()
     end
+
+    if conf.algorithm == "range_id" then
+        return get_range_id(conf.range_id)
+    end
+
     return next_id()
 end
 
@@ -218,7 +254,7 @@ function _M.rewrite(conf, ctx)
     local headers = ngx.req.get_headers()
     local uuid_val
     if not headers[conf.header_name] then
-        uuid_val = get_request_id(conf.algorithm)
+        uuid_val = get_request_id(conf)
         core.request.set_header(ctx, conf.header_name, uuid_val)
     else
         uuid_val = headers[conf.header_name]
diff --git a/docs/en/latest/plugins/request-id.md 
b/docs/en/latest/plugins/request-id.md
index 31469dee3..20f534d80 100644
--- a/docs/en/latest/plugins/request-id.md
+++ b/docs/en/latest/plugins/request-id.md
@@ -44,7 +44,9 @@ The Plugin will not add a unique ID if the request already 
has a header with the
 | ------------------- | ------- | -------- | -------------- | 
------------------------------- | 
---------------------------------------------------------------------- |
 | header_name         | string  | False    | "X-Request-Id" |                  
               | Header name for the unique request ID.                         
        |
 | include_in_response | boolean | False    | true           |                  
               | When set to `true`, adds the unique request ID in the response 
header. |
-| algorithm           | string  | False    | "uuid"         | ["uuid", 
"snowflake", "nanoid"] | Algorithm to use for generating the unique request ID. 
                |
+| algorithm           | string  | False    | "uuid"         | ["uuid", 
"snowflake", "nanoid", "range_id"] | Algorithm to use for generating the unique 
request ID.                 |
+| range_id.char_set      | string | False | 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789| The minimum 
string length is 6 | Character set for range_id |
+| range_id.length    | integer | False | 16             | Minimum 6 | Id 
length for range_id algorithm |
 
 ### Using snowflake algorithm to generate unique ID
 
diff --git a/docs/zh/latest/plugins/request-id.md 
b/docs/zh/latest/plugins/request-id.md
index 7ae62a841..88cbba76b 100644
--- a/docs/zh/latest/plugins/request-id.md
+++ b/docs/zh/latest/plugins/request-id.md
@@ -42,7 +42,9 @@ description: 本文介绍了 Apache APISIX request-id 插件的相关操作,
 | ------------------- | ------- | -------- | -------------- | ------ | 
------------------------------ |
 | header_name         | string  | 否 | "X-Request-Id" |                       | 
unique ID 的请求头的名称。         |
 | include_in_response | boolean | 否 | true          |                       | 
当设置为 `true` 时,将 unique ID 加入返回头。 |
-| algorithm           | string  | 否 | "uuid"         | ["uuid", "snowflake", 
"nanoid"] | 指定的 unique ID 生成算法。 |
+| algorithm           | string  | 否 | "uuid"         | ["uuid", "snowflake", 
"nanoid", "range_id"] | 指定的 unique ID 生成算法。 |
+| range_id.char_set      | string | 否 | 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ0123456789| 字符串长度最小为 6 | 
range_id 算法的字符集 |
+| range_id.length    | integer | 否 | 16             | 最小值为 6 | range_id 算法的 id 
长度 |
 
 ### 使用 snowflake 算法生成 unique ID
 
diff --git a/t/plugin/request-id2.t b/t/plugin/request-id2.t
new file mode 100644
index 000000000..a66c6b3dd
--- /dev/null
+++ b/t/plugin/request-id2.t
@@ -0,0 +1,182 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+use t::APISIX 'no_plan';
+
+worker_connections(1024);
+repeat_each(1);
+no_long_string();
+no_root_location();
+
+add_block_preprocessor(sub {
+    my ($block) = @_;
+
+    if (!$block->request) {
+        $block->set_value("request", "GET /t");
+    }
+});
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: check config with algorithm range_id
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "request-id": {
+                                "algorithm": "range_id",
+                                "range_id": {
+                                    "char_set": "abcdefg",
+                                    "length": 20
+                                }
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1982": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/opentracing"
+                }]]
+                )
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 2: add plugin with algorithm range_id
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                        "plugins": {
+                            "request-id": {
+                                "algorithm": "range_id"
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1982": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/opentracing"
+                }]]
+                )
+            if code >= 300 then
+                ngx.status = code
+            end
+            ngx.say(body)
+        }
+    }
+--- response_body
+passed
+
+
+
+=== TEST 3: add plugin with algorithm range_id
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin").test
+            local http = require "resty.http"
+            local v = {}
+            local ids = {}
+            local code, body = t('/apisix/admin/routes/1',
+                 ngx.HTTP_PUT,
+                 [[{
+                       "plugins": {
+                            "request-id": {
+                                "algorithm": "range_id",
+                                "range_id": {}
+                            }
+                        },
+                        "upstream": {
+                            "nodes": {
+                                "127.0.0.1:1982": 1
+                            },
+                            "type": "roundrobin"
+                        },
+                        "uri": "/opentracing"
+                }]]
+                )
+            if code >= 300 then
+                ngx.say("algorithm range_id is error")
+            end
+            for i = 1, 180 do
+                local th = assert(ngx.thread.spawn(function()
+                    local httpc = http.new()
+                    local uri = "http://127.0.0.1:"; .. ngx.var.server_port .. 
"/opentracing"
+                    local res, err = httpc:request_uri(uri,
+                        {
+                            method = "GET",
+                            headers = {
+                                ["Content-Type"] = "application/json",
+                            }
+                        }
+                    )
+                    if not res then
+                        ngx.log(ngx.ERR, err)
+                        return
+                    end
+                    local id = res.headers["X-Request-Id"]
+                    if not id then
+                        return -- ignore if the data is not synced yet.
+                    end
+                    if #id ~= 16 then
+                        ngx.say(id)
+                        ngx.say("incorrect length for id")
+                        return
+                    end
+                    local start, en = string.find(id, '[a-zA-Z0-9]*')
+                    if start ~= 1 or en ~= 16 then
+                        ngx.say("incorrect char set for id")
+                        ngx.say(id)
+                        return
+                    end
+                    if ids[id] == true then
+                        ngx.say("ids not unique")
+                        return
+                    end
+                    ids[id] = true
+                end, i))
+                table.insert(v, th)
+            end
+            for i, th in ipairs(v) do
+                ngx.thread.wait(th)
+            end
+            ngx.say("true")
+        }
+    }
+--- wait: 5
+--- response_body
+true

Reply via email to