Compare commits
450 Commits
cache-midd
...
master
Author | SHA1 | Date |
---|---|---|
innov | a1fa8b22de | |
bandl | a9fac2572b | |
bandl | 57caa66ef8 | |
bandl | d254a71560 | |
bandl | 07dd0f8874 | |
bandl | dafffdde2c | |
bandl | c6b14ced27 | |
bandl | b87799a88e | |
bandl | dcfae2353b | |
bandl | bf0c03a77f | |
bandl | a57eab1184 | |
bandl | ef4cbb0cee | |
bandl | f62a59b551 | |
bandl | a949ab2edc | |
bandl | 7ac9651ef3 | |
bandl | 19e1bb59a3 | |
bandl | c381c57374 | |
bandl | 3f337dba9b | |
bandl | a37097b3dd | |
bandl | d90c05296a | |
bandl | 2a556a9db6 | |
bandl | c0da22ef6f | |
bandl | cf4b24ea86 | |
bandl | 953daca82c | |
Pyroo | 5974dadd3e | |
bandl | 1baac521fa | |
Pyroo | d6792444a7 | |
bandl | 64a02b642e | |
bandl | a5ef559e14 | |
bandl | 0c8a17b21d | |
bandl | 0207878507 | |
bandl | 813b48b650 | |
bandl | cdd26736a5 | |
bandl | 40afd8057d | |
bandl | 08bc1892df | |
bandl | 5e89f37e40 | |
bandl | 6b2f3fb3be | |
bandl | 499322c080 | |
bandl | e5f217b3b0 | |
bandl | 113185d17c | |
bandl | 981a3341ef | |
bandl | af6426f83b | |
bandl | d68209c94c | |
bandl | 60cf8f5eb1 | |
bandl | 594f8acf32 | |
bandl | 366793d955 | |
bandl | 5105a62bca | |
bandl | 400d620aa4 | |
bandl | 25be4a1509 | |
bandl | 60de1a6ae9 | |
bandl | 55204575d7 | |
bandl | 2f81eab981 | |
bandl | 3eb515325d | |
bandl | 3f3b208db1 | |
bandl | 8b8fd58c09 | |
bandl | 62d3105273 | |
bandl | 51bd9b242f | |
bandl | f6eaae71b9 | |
bandl | 921078c61d | |
bandl | c8ef4c6e46 | |
bandl | c6273d084e | |
bandl | fd605d125f | |
bandl | c9dcb41cad | |
bandl | f7bb695e82 | |
bandl | 4e6c2ed22a | |
bandl | 0c08e40667 | |
bandl | 7fa66abbf0 | |
bandl | a910e4af21 | |
bandl | 51914aea8a | |
bandl | bbfd32cebc | |
bandl | 44bd5bc7cd | |
bandl | fcdb2310fe | |
bandl | 222bcc4eea | |
bandl | c3cff03b2b | |
bandl | 06baf3993d | |
bandl | 976215ee10 | |
bandl | 778d5152c8 | |
bandl | 5ce350f115 | |
bandl | 047c910278 | |
bandl | dcada2f2fe | |
bandl | 88774daede | |
bandl | 344c136586 | |
bandl | 4c9ab82123 | |
bandl | 2ed75832ba | |
bandl | 0f1142d434 | |
bandl | b6dedfa384 | |
bandl | 0f2b73e932 | |
bandl | 2f46dfaa2e | |
bandl | c867665b60 | |
bandl | b91966709b | |
bandl | 47cdf0859b | |
bandl | 0b9230094a | |
bandl | eccfd6a439 | |
bandl | f5c3b0e1db | |
bandl | 5ee502021d | |
bandl | 9fed552380 | |
bandl | 7d9081ce8e | |
bandl | 4ca09febb4 | |
bandl | be528cbb6d | |
bandl | 70b23849bc | |
bandl | 99133bf7ea | |
bandl | 1ca43cde6c | |
bandl | de59f13234 | |
bandl | 72add38cee | |
bandl | 3b61f55fe3 | |
bandl | 6fc2417de2 | |
bandl | 7aa39979f0 | |
bandl | 4ffa91ac6a | |
bandl | 170ba44d2d | |
bandl | ce888a1d0e | |
bandl | 787003d95a | |
bandl | 27542cf898 | |
bandl | 3bcd154177 | |
bandl | bed3f1893a | |
bandl | 200623bd29 | |
bandl | dce8739514 | |
bandl | 686c032f34 | |
bandl | 41e282de5d | |
bandl | 23b13afc86 | |
bandl | b4c3cc5a86 | |
bandl | 54520cb033 | |
bandl | c67e0c863c | |
bandl | ea8e10fcbf | |
bandl | 19a0259f58 | |
bandl | 511a66bd98 | |
bandl | 5642a00f61 | |
bandl | 1f85847243 | |
bandl | dab21a4ebc | |
bandl | 14c52da1ed | |
bandl | 5f188eaddf | |
bandl | bbc4c27027 | |
bandl | b6348f5992 | |
bandl | 404dc1fbbc | |
bandl | db615609cd | |
bandl | 46b029b339 | |
bandl | ac4fdd7309 | |
bandl | bff937700e | |
bandl | 2a69f393e5 | |
bandl | 417ddf1ccf | |
bandl | d78cb874ed | |
bandl | 06042b778c | |
bandl | 19562221f9 | |
bandl | 5d7df024e4 | |
bandl | 9298b77c7c | |
bandl | 3f4607fb58 | |
bandl | 09730e9ebf | |
bandl | cd1ba29f42 | |
bandl | cf9dc1da38 | |
bandl | fc60b2a779 | |
bandl | e81124c7e6 | |
bandl | ebfa948421 | |
bandl | b32606ee15 | |
bandl | 3c8d4fd89b | |
bandl | 9a1f1fe0ee | |
bandl | e894734418 | |
bandl | e404f670a0 | |
bandl | 4459beba61 | |
bandl | ab277fb66e | |
bandl | 0b781a178e | |
bandl | e96f21399c | |
bandl | 6a63bdca84 | |
bandl | f15792032a | |
bandl | 7ce1a55d0e | |
bandl | 4f6fb64ecc | |
bandl | 74e42e78ac | |
bandl | 8883abd461 | |
bandl | 8c5c594ac5 | |
bandl | 77988052ee | |
bandl | e6eb86de05 | |
bandl | f022ae9cbe | |
bandl | d42b01ff77 | |
bandl | a9dbb5169c | |
bandl | 15e1bb06af | |
bandl | 41ef546d95 | |
bandl | 70a246f84c | |
bandl | 2295fbcf40 | |
bandl | 3a4fc48f46 | |
bandl | 5b0a636e02 | |
bandl | fe096c9054 | |
bandl | a374638758 | |
bandl | 56d69f63af | |
bandl | aed507fc9a | |
bandl | 739cb56243 | |
bandl | 1a884ce9f0 | |
bandl | 576a7bbd41 | |
bandl | 623373f7ac | |
bandl | 4413ee6f92 | |
bandl | 4a887b0e58 | |
bandl | 74a85e518d | |
bandl | cb1e555986 | |
bandl | 780cf7d276 | |
bandl | e94a41ec73 | |
bandl | 6ef4654c63 | |
bandl | 6bd16eec06 | |
bandl | 21cac4639c | |
bandl | d17f8e243c | |
bandl | 95d3fdbd17 | |
bandl | ac8f748356 | |
bandl | 064ef3e50e | |
bandl | eb0014437b | |
bandl | 310e11c65b | |
bandl | 019322eb8f | |
bandl | a00f10c70e | |
bandl | 3c68787ff4 | |
bandl | 57e84b6dee | |
bandl | 5fe201ca32 | |
bandl | aade8e8edb | |
bandl | 6fdf250833 | |
bandl | d963c06576 | |
bandl | d6f1631d7b | |
bandl | 477613f0de | |
bandl | bd0e598f1a | |
bandl | 98787c8f03 | |
bandl | 1e4d611c77 | |
bandl | b97edc4cf1 | |
bandl | 91d93bf5be | |
bandl | ebdc5bd5b0 | |
bandl | 43392236b6 | |
bandl | 52c9b166f3 | |
bandl | 40374333fa | |
bandl | 3adeac539b | |
bandl | ec8a126581 | |
bandl | 4e78d08e2c | |
bandl | 2c854deb52 | |
bandl | 62eaa8edd0 | |
bandl | cbf7ba1933 | |
bandl | 32936576d3 | |
bandl | 57a655a708 | |
bandl | 554f7feef9 | |
bandl | 101059126c | |
bandl | ccf7179713 | |
bandl | 5934e88e03 | |
bandl | f7d4cee102 | |
bandl | ef5c088a49 | |
bandl | c8f23d1357 | |
bandl | 85e9a3b5f8 | |
bandl | 02bd151381 | |
bandl | 758f1bfec2 | |
bandl | e3c7546023 | |
bandl | b61794d74b | |
bandl | 5776e0ba6e | |
bandl | c4161e77d0 | |
bandl | e826ff4569 | |
K-on | d2866256dd | |
K-on | 5459c7710c | |
HuangJiaLuo | aebab3b3d7 | |
HuangJiaLuo | b39899e5d6 | |
HuangJiaLuo | 922fae0f78 | |
Sodesnei | 44dbb04f0b | |
Sodesnei | e2f00fa2ae | |
Sodesnei | ec8cea59a4 | |
bandl | ab257b2009 | |
黎白南 | e5ac4d1cf9 | |
黎白南 | 51517da519 | |
HuangJiaLuo | 73e91b3ff0 | |
HuangJiaLuo | dcce00a32d | |
HuangJiaLuo | 2500251699 | |
HuangJiaLuo | 29b9c8f3b6 | |
HuangJiaLuo | f119557eec | |
HuangJiaLuo | 5275be2b8e | |
HuangJiaLuo | 83bf49ec17 | |
HuangJiaLuo | cf1c90442b | |
Sodesnei | aac12f93f4 | |
Sodesnei | debde8a66a | |
Sodesnei | 95f165fb55 | |
Sodesnei | febd5501c4 | |
HuangJiaLuo | 8a6db79fd6 | |
HuangJiaLuo | 64b38044c8 | |
HuangJiaLuo | 843fcd27ca | |
HuangJiaLuo | a251cdb844 | |
Sodesnei | 4d9558c21f | |
Sodesnei | b182d7602d | |
Sodesnei | 99c3c56a5b | |
Sodesnei | 81d3bb8434 | |
Sodesnei | ce8f72040b | |
Sodesnei | 329513bd98 | |
Sodesnei | 2e04517066 | |
HuangJiaLuo | f1d2cbb0ee | |
HuangJiaLuo | c45c2682e0 | |
HuangJiaLuo | 929f931cd6 | |
黎白南 | b168eecbb4 | |
黎白南 | e98731c1b3 | |
黎白南 | 77d4b88c71 | |
Sodesnei | 1540651864 | |
Sodesnei | 166d1f20c1 | |
bandl | 96c8a6d53e | |
HuangJiaLuo | 83febdd482 | |
HuangJiaLuo | e3171a8b3e | |
bandl | 60abd336b1 | |
HuangJiaLuo | 428a8fa8f8 | |
HuangJiaLuo | 97833ed150 | |
HuangJiaLuo | f17cab2016 | |
HuangJiaLuo | d4d93a0e51 | |
HuangJiaLuo | f9ad4d914e | |
HuangJiaLuo | d08e50f4ce | |
HuangJiaLuo | 90b021bee2 | |
bandl | 63bd44da44 | |
黎白南 | d8dc56d95a | |
bandl | c36659da26 | |
黎白南 | 87ada5f981 | |
黎白南 | 880aba64d0 | |
黎白南 | 34dd0fe94f | |
HuangJiaLuo | 36e8efd682 | |
黎白南 | 692ad28380 | |
黎白南 | 0e2db14d32 | |
黎白南 | 5061b2e3da | |
黎白南 | b75aa1d141 | |
黎白南 | a706d57370 | |
bandl | 5292163b14 | |
bandl | c9cfa04725 | |
bandl | 4afe3dabb6 | |
bandl | 212e025b23 | |
bandl | 125b137ef6 | |
bandl | 67da63ac03 | |
bandl | 74ab13c756 | |
bandl | 26226eca28 | |
bandl | 1de8e1b141 | |
bandl | 8bcac6f739 | |
bandl | e6987546ae | |
bandl | 8e6f18f887 | |
bandl | 30c34cf30f | |
bandl | c27328ced4 | |
Sodesnei | 7c6c26c5fa | |
Sodesnei | 49496cf63c | |
Sodesnei | bd804e7105 | |
Sodesnei | 1c9c437a0f | |
Sodesnei | 0bdbe06376 | |
Sodesnei | ea36d370a7 | |
Sodesnei | 373de8b282 | |
K-on | 15cede5780 | |
HuangJiaLuo | e637cccaed | |
bandl | f7508d67a3 | |
HuangJiaLuo | b95fb85ad6 | |
HuangJiaLuo | 1774c9f230 | |
HuangJiaLuo | 477adec1bb | |
HuangJiaLuo | ca04ba1686 | |
HuangJiaLuo | 71ddeb4772 | |
HuangJiaLuo | 75e1251d22 | |
HuangJiaLuo | dbc0467de4 | |
HuangJiaLuo | 29c5aca40d | |
HuangJiaLuo | 99dd878bb3 | |
HuangJiaLuo | 96d5a9acc9 | |
HuangJiaLuo | 47a49b1fdb | |
HuangJiaLuo | 768f3df70e | |
bandl | a556840f9b | |
bandl | 2c11d500fd | |
bandl | a323f7e8a9 | |
bandl | 5888e2e15a | |
bandl | 57bdec3c1d | |
bandl | ae5a0531d8 | |
bandl | 04cb2a1ed1 | |
Sodesnei | 2c6a6a6848 | |
Sodesnei | 488d84580e | |
bandl | 26f3f9f663 | |
Sodesnei | 82e358e268 | |
bandl | c11d10d6e2 | |
bandl | 600ecb644e | |
bandl | 187280bc2c | |
bandl | ad0cdedba9 | |
bandl | 0903477c22 | |
bandl | 0677c56492 | |
bandl | f53eea9c22 | |
bandl | 0b8e2a104f | |
bandl | 748f61830b | |
bandl | 05bd410900 | |
bandl | d4a73b93d3 | |
bandl | 70319ae2b1 | |
Sodesnei | ea9a660740 | |
bandl | 0458ed3d21 | |
bandl | f4327aa5b6 | |
bandl | 8dd5879b2a | |
bandl | 060c1d2bfb | |
bandl | 8d663fe920 | |
bandl | a8bbbc70a4 | |
bandl | 175bddf527 | |
bandl | eb53a976e2 | |
bandl | bcacc83df6 | |
bandl | 3d7df7149a | |
bandl | ec9d3a1a71 | |
bandl | f0835b3344 | |
bandl | fc47f3eca0 | |
bandl | 98ef750a67 | |
bandl | d1113821c9 | |
bandl | 6d26969cae | |
bandl | 36d18c1368 | |
bandl | ea83b319de | |
bandl | 24d0ef2611 | |
HuangJiaLuo | 5d66e47e74 | |
bandl | 6637f4c77e | |
bandl | cc57179c11 | |
bandl | a9ab92c16a | |
bandl | ddd7a8a5ed | |
bandl | e3acfcd0fe | |
bandl | 6eec180306 | |
bandl | 76c203c37a | |
yu_lang | f3e894a068 | |
yu_lang | 53fe26db48 | |
yu_lang | f410738b27 | |
bandl | b9060a64d5 | |
yu_lang | cf4b5cd63c | |
yu_lang | 8bc30d3b85 | |
bandl | 2e9216d894 | |
HuangJiaLuo | 77cab55402 | |
bandl | 23baebe2d7 | |
HuangJiaLuo | 09b8907085 | |
bandl | b03d096b53 | |
bandl | 20b2272e7c | |
bandl | 4b27125092 | |
bandl | 63d6f66770 | |
yu_lang | 1de6231a17 | |
yu_lang | 27fbb69034 | |
HuangJiaLuo | d9a9da6dee | |
bandl | fa2c67d140 | |
bandl | 81f85009ab | |
bandl | c1ca0a499f | |
yu_lang | 4653e6f27c | |
bandl | 8714fc8b8f | |
bandl | 9b9ece8f54 | |
bandl | 9cbd06227d | |
bandl | 7837edb92e | |
bandl | f910e2c503 | |
bandl | 4405512540 | |
bandl | 221dbdd6d4 | |
bandl | b902c8cc1f | |
bandl | 40dd0dd91a | |
bandl | 414cd6d9a7 | |
bandl | c84873208b | |
bandl | 8cfed8b325 | |
bandl | aadb43cfd9 | |
bandl | 6b80b30f31 | |
bandl | 0b88178df0 | |
bandl | 136fc48206 | |
bandl | fd80e3ddde | |
bandl | 6817eccff6 | |
bandl | 30e182d018 | |
bandl | 8c114bcb9a | |
bandl | 6453b2a0ce | |
bandl | a5a01b8e33 | |
bandl | 13a3291e9e | |
bandl | 781fc4b6b7 | |
bandl | 087bec4861 | |
yu_lang | c321d6865d | |
yu_lang | 78ee204877 | |
yu_lang | 9fd9be29a3 | |
bandl | f768f361c1 | |
bandl | c699fa0527 | |
bandl | 2c9e6784b1 | |
bandl | 9262c6e8c5 | |
bandl | 7e8108bc73 | |
bandl | 2c0eeb89df |
Before Width: | Height: | Size: 26 KiB |
|
@ -7,7 +7,7 @@
|
|||
### 描述(做了什么,变更了什么)
|
||||
|
||||
|
||||
### 测试用例(新增、改动、可能影响的功能)
|
||||
### 影响到的模块
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,8 +5,17 @@
|
|||
*.so
|
||||
*.dylib
|
||||
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
|
||||
# build file
|
||||
/bin/storage
|
||||
/bin/gateway
|
|
@ -1,8 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/wheat-cache.iml" filepath="$PROJECT_DIR$/.idea/wheat-cache.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
Before Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,7 @@
|
|||
FROM ubuntu:18.04
|
||||
|
||||
WORKDIR /home/src/gitee.com/wheat-os/wheat-cache
|
||||
ADD . /home/src/gitee.com/wheat-os/wheat-cache
|
||||
|
||||
RUN mkdir /etc/wheat-cache
|
||||
RUN mv /home/src/gitee.com/wheat-os/wheat-cache/conf/wheat-cache.yaml /etc/wheat-cache/
|
|
@ -0,0 +1,22 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"gitee.com/wheat-os/wheatCache/client/middle"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func newWheatClient(targer string, opt ...middle.ClientMiddle) (proto.CommServerClient, error) {
|
||||
|
||||
interceptor := middle.GetUnaryInterceptor(opt...)
|
||||
comm, err := grpc.Dial(targer, grpc.WithInsecure(), grpc.WithUnaryInterceptor(interceptor))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return proto.NewCommServerClient(comm), nil
|
||||
}
|
||||
|
||||
func NewWheatClient(targer string, opt ...middle.ClientMiddle) (proto.CommServerClient, error) {
|
||||
return newWheatClient(targer, opt...)
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/client/middle"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
cli, err := NewWheatClient("127.0.0.1:5891", middle.WithUnaryColonyClient)
|
||||
require.NoError(t, err)
|
||||
ctx := context.Background()
|
||||
|
||||
bKey := proto.NewBaseKey("apple")
|
||||
resp, err := cli.Set(ctx, &proto.SetRequest{
|
||||
Key: bKey,
|
||||
Val: "yyyy",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp.Result, "yyyy")
|
||||
|
||||
getResp, err := cli.Get(ctx, &proto.GetRequest{
|
||||
Key: bKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, getResp.Result, "yyyy")
|
||||
}
|
||||
|
||||
func TestClientGet(t *testing.T) {
|
||||
cli, err := NewWheatClient("127.0.0.1:5891", middle.WithUnaryColonyClient)
|
||||
require.NoError(t, err)
|
||||
ctx := context.Background()
|
||||
|
||||
bKey := &proto.BaseKey{
|
||||
Key: "apple",
|
||||
}
|
||||
|
||||
getResp, err := cli.Get(ctx, &proto.GetRequest{
|
||||
Key: bKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, getResp.Result, "yyyy")
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package middle
|
||||
|
||||
import "context"
|
||||
|
||||
// type UnaryClientInterceptor func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error
|
||||
type ClientMiddle func(ctx context.Context, method string, req, reply interface{}, header map[string]string) error
|
|
@ -0,0 +1,53 @@
|
|||
package middle
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func WithUnaryColonyClient(ctx context.Context, method string, req, reply interface{}, header map[string]string) error {
|
||||
key, ok := req.(proto.GetKeyBaseInterface)
|
||||
if !ok {
|
||||
return status.Errorf(codes.Unknown, "key base err")
|
||||
}
|
||||
if header == nil {
|
||||
return nil
|
||||
}
|
||||
// meta 解析会出现 全部小写问题
|
||||
header[proto.BaseKeyMethodKey] = key.GetKey().Key
|
||||
return nil
|
||||
}
|
||||
|
||||
func getKeyByKeyMapvalue(m map[string]string) []string {
|
||||
l := make([]string, 0)
|
||||
for key, value := range m {
|
||||
l = append(l, key, value)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func GetUnaryInterceptor(middleOpts ...ClientMiddle) grpc.UnaryClientInterceptor {
|
||||
return func(ctx context.Context, method string, req, reply interface{},
|
||||
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
// 加载中间件
|
||||
header := make(map[string]string)
|
||||
for _, mid := range middleOpts {
|
||||
err := mid(ctx, method, req, reply, header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
lm := getKeyByKeyMapvalue(header)
|
||||
|
||||
headerData := metadata.Pairs(lm...)
|
||||
ctxH := metadata.NewOutgoingContext(ctx, headerData)
|
||||
|
||||
return invoker(ctxH, method, req, reply, cc, opts...)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
linuxPath = "/etc/wheat-cache/"
|
||||
)
|
||||
|
||||
var confLock sync.Once
|
||||
|
||||
func init() {
|
||||
confLock.Do(func() {
|
||||
setDefaultConfValue()
|
||||
err := LoadConf("")
|
||||
switch err.(type) {
|
||||
case nil:
|
||||
case viper.ConfigFileNotFoundError:
|
||||
formatPath := []string{linuxPath}
|
||||
log.Fatalf("the profile could not be read, read path:%v", formatPath)
|
||||
default:
|
||||
log.Fatalf("the resolution of the profile failed, err: %v", err)
|
||||
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func setDefaultConfValue() {
|
||||
// 设置一些默认值
|
||||
viper.SetDefault("version", "base-01")
|
||||
defaultStorage()
|
||||
}
|
||||
|
||||
func LoadConf(path string) error {
|
||||
if path != "" {
|
||||
viper.AddConfigPath(path)
|
||||
}
|
||||
viper.SetConfigName("wheat-cache")
|
||||
|
||||
// 添加默认读取地址
|
||||
// linux
|
||||
viper.AddConfigPath(linuxPath)
|
||||
|
||||
viper.SetConfigType("yaml")
|
||||
|
||||
err := viper.ReadInConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package conf
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestConf(t *testing.T) {
|
||||
|
||||
// 外部导入 conf.yaml 需要导入 conf 包
|
||||
// 每次迁移文件时, 使用 sudo make init-conf来将yam文件迁移到指定的文件夹下
|
||||
// get 使用, 读取 public_conf 配置文件
|
||||
h := viper.Get("storage.host")
|
||||
require.Equal(t, h, "127.0.0.1")
|
||||
|
||||
h = viper.Get("env")
|
||||
require.Equal(t, h, "dev")
|
||||
|
||||
// set 使用
|
||||
viper.Set("host", "1222")
|
||||
host := viper.GetString("host")
|
||||
require.Equal(t, host, "1222")
|
||||
}
|
||||
|
||||
func TestMiddleConf(t *testing.T) {
|
||||
ct := viper.GetStringSlice("plugins-control.logcontext")
|
||||
require.Equal(t, ct, []string{"logMiddle"})
|
||||
|
||||
d := viper.GetInt("middleware-driver.driverCount")
|
||||
require.Equal(t, d, 1000)
|
||||
c := viper.GetInt("middleware-driver.middleConsumerCount")
|
||||
require.Equal(t, c, 5)
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package conf
|
||||
|
||||
import "github.com/spf13/viper"
|
||||
|
||||
func defaultStorage() {
|
||||
// aof
|
||||
viper.SetDefault("storage.aof-path", "/etc/wheat-cache/wheat.aof")
|
||||
viper.SetDefault("storage.aof-flush-time", 5)
|
||||
viper.SetDefault("storage.aof-check-time", 1)
|
||||
viper.SetDefault("storage.aof-check-freq", 20)
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
version: 'v1.0'
|
||||
|
||||
env: 'dev'
|
||||
|
||||
storage:
|
||||
host: '0.0.0.0'
|
||||
port: 5890
|
||||
timeOut: 2 # second
|
||||
|
||||
aof-codec: "b16" # 目前只实现了 b16 编码方案。
|
||||
aof-path: "/etc/wheat-cache/wheat.aof"
|
||||
aof-flush-time: 5 # second , 每 5 秒刷新缓冲区的内容到磁盘。
|
||||
aof-check-time: 1 # 每 1 second 执行一次 io 检查
|
||||
aof-check-freq: 20 # 在一个 aof-check-time 周期内,出现超过 aof-check-freq 的 IO 操作会刷新磁盘
|
||||
|
||||
|
||||
# clearSize and maxSize must be Int
|
||||
lruCache:
|
||||
clearSize: "512mb"
|
||||
maxSize: "1GB"
|
||||
eventDriverSize: 2000
|
||||
workTime: 1
|
||||
detachNum: 300
|
||||
|
||||
|
||||
logPrint:
|
||||
stath: ["error"]
|
||||
|
||||
|
||||
middleware-driver:
|
||||
driverCount: 1000
|
||||
middleConsumerCount: 5
|
||||
|
||||
# Register the message push type
|
||||
# 在这里注册消息推送类型,
|
||||
plugins-control:
|
||||
|
||||
# log-context: Logs generated by storage or gateway are pushed through this message
|
||||
# log-context: storage 或者 gateway 产生的日志通过这个消息推送
|
||||
log-context: [ "mock-plugins" ]
|
||||
|
||||
# lru-clean-context: Lru is pushed through this message when data cleansing occurs
|
||||
# lru-clean-context: Lru 发生数据清理时通过这个消息推送
|
||||
lru-clean-context: ["mock-plugins"]
|
||||
|
||||
# lru-ttl-context: Lru is pushed through this message when data expires
|
||||
# lru-ttl-context: Lru 发生数据过期时通过这个消息推送
|
||||
lru-ttl-context: ["mock-plugins"]
|
||||
|
||||
# plugins-info-context:All plugins information for the current project
|
||||
# plugins-info-context: 当前项目全部的插件信息
|
||||
plugins-infos-context: ["mock-plugins"]
|
||||
|
||||
gateway:
|
||||
host: '0.0.0.0'
|
||||
port: 5891
|
||||
target: ["127.0.0.1:5890"]
|
||||
|
||||
mock-plugin:
|
||||
pprof-addr: "127.0.0.1:8000"
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="94" height="20" role="img" aria-label="license: AFL3.0"><title>license: AFL3.0</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="94" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="47" height="20" fill="#555"/><rect x="47" width="47" height="20" fill="#97ca00"/><rect width="94" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="245" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">license</text><text x="245" y="140" transform="scale(.1)" fill="#fff" textLength="370">license</text><text aria-hidden="true" x="695" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">AFL3.0</text><text x="695" y="140" transform="scale(.1)" fill="#fff" textLength="370">AFL3.0</text></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 37 KiB |
|
@ -0,0 +1,2 @@
|
|||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="88" height="20" role="img" aria-label="Wheat: Cache"><title>Wheat: Cache</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="88" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="45" height="20" fill="#555"/><rect x="45" width="43" height="20" fill="#a4a61d"/><rect width="88" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="235" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">Wheat</text><text x="235" y="140" transform="scale(.1)" fill="#fff" textLength="350">Wheat</text><text aria-hidden="true" x="655" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="330">Cache</text><text x="655" y="140" transform="scale(.1)" fill="#fff" textLength="330">Cache</text></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 8.9 KiB |
|
@ -0,0 +1,2 @@
|
|||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="86" height="20" role="img" aria-label="version: v1.1"><title>version: v1.1</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="86" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="51" height="20" fill="#555"/><rect x="51" width="35" height="20" fill="#007ec6"/><rect width="86" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="265" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">version</text><text x="265" y="140" transform="scale(.1)" fill="#fff" textLength="410">version</text><text aria-hidden="true" x="675" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="250">v1.1</text><text x="675" y="140" transform="scale(.1)" fill="#fff" textLength="250">v1.1</text></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,11 @@
|
|||
### Cache 分布式方案-Getway
|
||||
|
||||
|
||||
|
||||
![getway方案](https://gitee.com/timedb/img/raw/master/images/getway方案.svg)
|
||||
|
||||
|
||||
|
||||
1. single 集群分布式方案中,使用 getway 方向代理客户端的 grpc 请求, 通过 hash 环实现 分布式。
|
||||
2. 集群模式中, 通过主从来 实现 cache 的备份问题,提高容灾性。
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
### 构建工具文档
|
||||
|
||||
#### dcgen
|
||||
1. 根据结构体接口模板生成 proto 文件
|
||||
2. 迁移 proto 到 pkg/proto 下
|
||||
3. 更新结构体常量
|
||||
|
||||
>PS : 开发一个 storage 的新接口时一般有以下步骤
|
||||
>1. 修改 storage 接口配置文件
|
||||
>2. make dcgen
|
||||
>3. 修改生成的 proto 文件
|
||||
>4. make dcgen
|
||||
>5. 添加 storage 的操作接口
|
||||
|
||||
|
||||
#### build-storage
|
||||
编译并且生成 /bin/storage
|
||||
|
||||
#### build-gateway
|
||||
编译并且生成 /bin/gateway
|
||||
|
||||
#### install
|
||||
1. 安装项目,需要 sudo
|
||||
|
||||
#### storage
|
||||
根据配置文件启动 storage
|
||||
|
||||
#### gateway
|
||||
根据配置文件启动 gateway
|
||||
|
||||
#### init-conf
|
||||
根据配置文件文档初始化配置文件到 /etc/wheat-cache/wheat-cache.yaml
|
|
@ -0,0 +1,13 @@
|
|||
### 事件驱动 2.0
|
||||
|
||||
### event 1.0 存在的问题
|
||||
事件驱动 1.0 在 相互关联访问时,会发生 死锁问题, 导致一个事件执行周期失败
|
||||
|
||||
### event 2.0 新特性
|
||||
- 异步事件支持
|
||||
- 挂起操作
|
||||
|
||||
|
||||
### event 2.0 设计图
|
||||
![](../../_icon/event.svg)
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
### 事件驱动使用文档
|
||||
|
||||
|
||||
|
||||
- 包目录: pkg/event
|
||||
- 使用场景, 异步推送数据
|
||||
|
||||
|
||||
|
||||
#### 事件驱动基本概念
|
||||
|
||||
- event
|
||||
|
||||
event 是事件驱动的事件部分, 主要负责一些信息的传递, 一共分为,有等待和无等待的事件, 无等待事件 consumer 消费事件后,不会给 produce 回复, 有等待事件, 支持事件消费后, 向 produce 发送一个回复。
|
||||
|
||||
- driver
|
||||
|
||||
driver 是事件的驱动, 主要复制连接 produce, 以及 consumer, 其中维护了一个 event 的队列。
|
||||
|
||||
- produce
|
||||
|
||||
produce 主要负责 推送 事件, 每个 produce 都需要维护一个 事件驱动通过 driver 来进行数据的推送。
|
||||
|
||||
- consumer
|
||||
|
||||
consumer 负责接收事件, 每个 consumer 都需要注册一个 事件驱动 来获取 event。
|
||||
|
||||
####
|
||||
|
||||
#### 应用场景
|
||||
|
||||
事件驱动主要用于 异步消息的推送(目前的实现也支持 同步的消息实现), 一般来说 produce 发送 event 后 event 被消费过程会完全于 produce 无关。
|
||||
|
||||
|
||||
|
||||
#### 无返回 event 使用例子
|
||||
|
||||
我们使用 借书为例子使用, 假设 A 要把 书 S 交还给 B, 他们约定, A 把书 S 放到图书馆, B 在空闲时去图书馆取出书 S。
|
||||
|
||||
```go
|
||||
func TestNewConsumer(t *testing.T) {
|
||||
// 定义一个图书馆
|
||||
type Library struct {
|
||||
driver DriverInterface
|
||||
}
|
||||
library := &Library{
|
||||
driver: NewDriver(100),
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
// 定义 A
|
||||
type A struct {
|
||||
produce ProduceInterface
|
||||
}
|
||||
|
||||
a := &A{
|
||||
produce: NewProduce(library.driver),
|
||||
}
|
||||
|
||||
// 定义 B
|
||||
type B struct {
|
||||
consumer ConsumerInterface
|
||||
}
|
||||
|
||||
b := &B{
|
||||
consumer: NewConsumer(library.driver),
|
||||
}
|
||||
|
||||
// 定义书 S 并且添加一些描述
|
||||
book := NewEvent("S")
|
||||
book.SetMsg("title", "hello world")
|
||||
book.SetCtxValue("pages", 120)
|
||||
|
||||
// A 把书 S 放到图书馆
|
||||
go func() {
|
||||
a.produce.Call(ctx, book)
|
||||
}()
|
||||
|
||||
// 模拟 B 去图书馆拿书
|
||||
book = b.consumer.Receive(ctx)
|
||||
fmt.Println(book.GetMsg("title"))
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 有返回event的使用例子
|
||||
|
||||
在上述流程的情景下, 我们添加一些条件, B 拿到书以后检查书是否损坏,如果损坏, 需要告诉 A 书损坏情况。
|
||||
|
||||
```go
|
||||
func TestNewConsumer(t *testing.T) {
|
||||
// 定义一个图书馆
|
||||
type Library struct {
|
||||
driver DriverInterface
|
||||
}
|
||||
library := &Library{
|
||||
driver: NewDriver(100),
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
// 定义 A
|
||||
type A struct {
|
||||
produce ProduceInterface
|
||||
}
|
||||
|
||||
a := &A{
|
||||
produce: NewProduce(library.driver),
|
||||
}
|
||||
|
||||
// 定义 B
|
||||
type B struct {
|
||||
consumer ConsumerInterface
|
||||
}
|
||||
|
||||
b := &B{
|
||||
consumer: NewConsumer(library.driver),
|
||||
}
|
||||
|
||||
// 定义书 S 并且添加一些描述
|
||||
book := NewEvent("S")
|
||||
book.SetMsg("title", "hello world")
|
||||
book.SetValue("pages", 120)
|
||||
|
||||
// A 把书 S 放到图书馆
|
||||
go func() {
|
||||
book.InitWaitEvent()
|
||||
a.produce.Call(ctx, book)
|
||||
|
||||
// A 等待 B 的回复, 但是他最多只会等待 B 2个小时
|
||||
res, err := book.StartWaitEvent(2 * time.Hour)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(res)
|
||||
}()
|
||||
|
||||
// 模拟 B 去图书馆拿书
|
||||
book = b.consumer.Receive(ctx)
|
||||
fmt.Println(book.GetMsg("title"))
|
||||
|
||||
// 书完好
|
||||
book.ExecWorkAndSendResult(func() (interface{}, error) {
|
||||
// b 检查书
|
||||
return "OK", nil
|
||||
})
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
![](https://gitee.com/HuangJiaLuo/imgbed/raw/master/LRUdesign.svg)
|
||||
|
||||
EventP : 生产事件
|
||||
|
||||
EventQ : 事件队列
|
||||
|
||||
Event CP : 清理事件
|
|
@ -0,0 +1,5 @@
|
|||
### RDB + AOF 的事务解决方案
|
||||
|
||||
|
||||
|
||||
![事务RDB方案](https://gitee.com/timedb/img/raw/master/images/事务RDB方案.svg)
|
|
@ -0,0 +1,47 @@
|
|||
### 中间件调用
|
||||
|
||||
|
||||
### 创建事件
|
||||
|
||||
event := event.NewEvent("logcontext")
|
||||
|
||||
|
||||
### 创建驱动
|
||||
|
||||
middleware := NewMiddleWare()
|
||||
|
||||
### 将事件推入驱动
|
||||
|
||||
middleware.eventProduce.Call(ctx, event)
|
||||
|
||||
|
||||
### 获取驱动的事件
|
||||
middleware.eventConsumer.Reciver(ctx)
|
||||
|
||||
|
||||
|
||||
### 插件接口
|
||||
type MiddleToolsInterface interface {
|
||||
Init() // 初始化
|
||||
Exec(interface{}) (interface{}, error) // 处理用户发送事件
|
||||
Name() string // 获取中间件名称
|
||||
Describe() string // 描述
|
||||
}
|
||||
|
||||
### 插件的New方法规定为 NewMiddleWare()
|
||||
每个插件都要定义 NewMiddleWare()
|
||||
|
||||
|
||||
|
||||
### 将插件名 “logMiddle” 注册到配置文件wheat-cache.yaml,其他插件注册
|
||||
plugins-control:
|
||||
logcontext: ["logMiddle"]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
### 结构体开发文档
|
||||
|
||||
#### 基础结构体开发
|
||||
|
||||
- 基础结构体放到 /pkg/structure。
|
||||
|
||||
- 每个结构 类型都以 x 结尾,如 listx, stringx。
|
||||
|
||||
- 在 pkg/structure/define.go 文件中添加对应结构体的接口,主要为 了保证项目可以扩展线程安全结构体, 以及结构体接口的实现, 目前 lru 采用 single 模式, 可以只开发 single 的结构体,如 stringxSingle。
|
||||
|
||||
- 请在结构体包中 补充单元测试。
|
||||
|
||||
#### 目前实现结构体接口说明
|
||||
|
||||
> ps: 所有的详细用法都可以查看单元测试文件。
|
||||
|
||||
```go
|
||||
// stringx
|
||||
type StringXInterface interface {
|
||||
KeyBaseInterface
|
||||
// 重新设置一个 值
|
||||
Set(string) (string, UpdateLength)
|
||||
// 获取值的 string 形式
|
||||
Get() string
|
||||
// 值自动增加 一个值,只对 float 和 string 有效
|
||||
Add(int32) (string, error)
|
||||
// 值自动增加 减少值,只对 float 和 string 有效
|
||||
Reduce(int32) (string, error)
|
||||
// 使用位图类型
|
||||
Setbit(int32, bool) UpdateLength
|
||||
Getbit(int32) (bool, error)
|
||||
// 获取字符串的切片
|
||||
Getrange(start, end int32) (string, error)
|
||||
GetLength() int
|
||||
}
|
||||
|
||||
// listx
|
||||
type ListXInterface interface {
|
||||
KeyBaseInterface
|
||||
LPush(...string) UpdateLength
|
||||
RPush(...string) UpdateLength
|
||||
LPop(int) ([]string, UpdateLength)
|
||||
RPop(int) ([]string, UpdateLength)
|
||||
Index(int) (string, error)
|
||||
// 插入一组数据, bool 类型表示是否右插(尾插),false 时采用左插(头插)
|
||||
Insert(int, bool, ...string) (UpdateLength, error)
|
||||
Length() int
|
||||
// 切片, O(n)复杂度
|
||||
Slice(start, end int) (UpdateLength, error)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### structure.Value 类型
|
||||
- 结构体的数据区域全部使用 structure.Value 类型存储。
|
||||
- structure.Value 主要实现了 sting, int64, float64 的存储接口。
|
||||
- structure.Value 非常容易计算内存占用。
|
||||
- structure.UpdateLength 指的是在进行某一个操作以后,内存大小的变化。
|
||||
- 为了保证 lru 的存储效率,lru 不会去遍历全部的 key 来重新计算大小,而是根据 UpdateLength 来动态更新 lru 的大小,具体实现在 dao 中。
|
||||
- structure.Value 类型的使用方法可以在 pkg/structure/value_test.go 中获取。
|
|
@ -0,0 +1,46 @@
|
|||
### 快速进行 storage 开发
|
||||
|
||||
#### 开发环境
|
||||
- ubuntu18, 可以使用 wsl
|
||||
- go1.15+, python3
|
||||
- jinja2
|
||||
- go mod
|
||||
- protobuf 3.17.3
|
||||
- protoc-gen-go v1.26.0
|
||||
|
||||
#### storage 执行流程
|
||||
![](../_icon/storage-dao.svg)
|
||||
#### 分层,简介
|
||||
```sh
|
||||
.
|
||||
├── cmd # storage 启动函数
|
||||
│ └── root.go
|
||||
├── dao # 实际处理层,接口实现全部再 dao 层里实现
|
||||
│ ├── dao.go
|
||||
│ ├── dao_test.go
|
||||
│ ├── interface.gen.go
|
||||
│ ├── listx.go # listx 相关功能
|
||||
│ └── stringx.go
|
||||
├── main.go
|
||||
├── service # 接口层,由 gen-service 自动生成
|
||||
│ ├── define.go
|
||||
│ ├── single.go
|
||||
│ └── single_service.gen.go
|
||||
└── temp # 开发模板层
|
||||
├── const.gen.go
|
||||
├── const.template
|
||||
├── dao.template
|
||||
├── service.template
|
||||
└── tem.yaml
|
||||
```
|
||||
|
||||
#### 快速开发接口
|
||||
|
||||
> [快速开发视频 blibli](https://www.bilibili.com/video/BV1HL4y1v7ps)
|
||||
|
||||
1. 修改 temp/tem.yaml 文件,添加新接口
|
||||
2. 在项目根目录执行 `make dcgen` 生成 proto 原始结构
|
||||
3. 修改对应新添加接口的 proto 文件,再次执行 `make dcgen` 完成 proto 迁移
|
||||
4. 执行 `make gen-service` 生成 dao 接口
|
||||
5. 完成 新 dao 层接口, 根据需要添加单元测试。
|
||||
6. 使用 make install 编译并且安装项目
|
|
@ -0,0 +1,6 @@
|
|||
### 前端技术选择
|
||||
- react框架
|
||||
- 组件(antd或React-bootstrap或其他css组件)
|
||||
- 图表库(BizCharts)
|
||||
- protobufjs
|
||||
- grafana
|
|
@ -0,0 +1,54 @@
|
|||
### 单元测试文档
|
||||
|
||||
#### 样例
|
||||
```go
|
||||
package dao
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/lru"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// 规范1. 每个 package 应该都至少有一个单测
|
||||
|
||||
// 规范2. 包里有公用的 mock 数据应该分离出来。
|
||||
func mockData(t *testing.T, d *Dao) {
|
||||
|
||||
values := []string{"1", "1.3", "abcdefg"}
|
||||
|
||||
for _, val := range values {
|
||||
key := &proto.BaseKey{
|
||||
Key: val,
|
||||
}
|
||||
_, err := d.Set(key, val)
|
||||
|
||||
// 规范3. 使用 require 包来完成单测
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 规范4. 单元测试应该尽可能覆盖全部情况,不要使用依赖注入。
|
||||
func TestDao_Reduce(t *testing.T) {
|
||||
lruCache := lru.NewLRUCache()
|
||||
dao := NewDao(lruCache)
|
||||
mockData(t, dao)
|
||||
|
||||
resp, err := dao.Reduce(&proto.BaseKey{Key: "1"}, 2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp, "-1")
|
||||
|
||||
resp, err = dao.Reduce(&proto.BaseKey{Key: "1.3"}, 2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp, "-0.70")
|
||||
|
||||
_, err = dao.Reduce(&proto.BaseKey{Key: "abcdefg"}, 2)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
|
||||
```
|
|
@ -0,0 +1,119 @@
|
|||
### 开发流程
|
||||
|
||||
|
||||
|
||||
- 拉取 master 到本地
|
||||
|
||||
```
|
||||
git fetch origin master && git rebase origin/master
|
||||
```
|
||||
|
||||
- 查看本地更改 commit
|
||||
```
|
||||
git log
|
||||
```
|
||||
|
||||
- 添加分支
|
||||
|
||||
```sh
|
||||
# name-(feat, fix, doc)-(mode)-(task)
|
||||
git checkout -b doc-pro-git-doc
|
||||
```
|
||||
|
||||
- do task
|
||||
|
||||
- 提交 检查
|
||||
|
||||
```
|
||||
git push origin doc-pro-git-doc
|
||||
```
|
||||
|
||||
- 监听文件
|
||||
|
||||
```
|
||||
git add .
|
||||
```
|
||||
|
||||
- 添加 commit
|
||||
|
||||
```
|
||||
git commit -m "init doc"
|
||||
```
|
||||
|
||||
>**commit message格式**
|
||||
>
|
||||
>```text
|
||||
><type>(<scope>): <subject>
|
||||
>```
|
||||
>
|
||||
>**type(必须)**
|
||||
>
|
||||
>用于说明git commit的类别,只允许使用下面的标识。
|
||||
>
|
||||
>feat:新功能(feature)。
|
||||
>
|
||||
>fix:修复bug,可以是QA发现的BUG,也可以是研发自己发现的BUG。
|
||||
>
|
||||
>doc:文档(documentation)。
|
||||
>
|
||||
>style:格式(不影响代码运行的变动)。
|
||||
>
|
||||
>refactor:重构(即不是新增功能,也不是修改bug的代码变动)。
|
||||
>
|
||||
>perf:优化相关,比如提升性能、体验。
|
||||
>
|
||||
>test:增加测试。
|
||||
>
|
||||
>chore:构建过程或辅助工具的变动。
|
||||
>
|
||||
>revert:回滚到上一个版本。
|
||||
>
|
||||
>merge:代码合并。
|
||||
|
||||
|
||||
|
||||
- 提交PR (remove)
|
||||
|
||||
```
|
||||
添加描述, 提交PR
|
||||
```
|
||||
|
||||
- 解决问题
|
||||
|
||||
- 整理 commit
|
||||
|
||||
- 整理
|
||||
|
||||
```shell
|
||||
git rebase -i origin/master
|
||||
f:
|
||||
# 回调
|
||||
git rebase --abort
|
||||
|
||||
# 继续
|
||||
|
||||
```
|
||||
|
||||
- 强行推送
|
||||
|
||||
```
|
||||
git push -f origin doc-pro-git-doc
|
||||
```
|
||||
|
||||
- 重做
|
||||
|
||||
```sh
|
||||
git log
|
||||
# 7e8108bc7347ef6e2f01d6bc1d1f249afc82a486
|
||||
|
||||
git reset 7e8108bc7347ef6e2f01d6bc1d1f249afc82a486
|
||||
```
|
||||
|
||||
- 合并冲突
|
||||
|
||||
```sh
|
||||
# B 分支名称
|
||||
git pull origin B
|
||||
```
|
||||
|
||||
-
|
|
@ -0,0 +1,69 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
||||
wheatCodec "gitee.com/wheat-os/wheatCache/gateway/codec"
|
||||
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
|
||||
"gitee.com/wheat-os/wheatCache/gateway/proxy"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/logx"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/util/server"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "getway",
|
||||
Short: "getway",
|
||||
Long: `start getway server`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
host := viper.GetString("gateway.host")
|
||||
port := viper.GetInt("gateway.port")
|
||||
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
|
||||
if err != nil {
|
||||
logx.Panic("get gateway addr err:%v", err)
|
||||
}
|
||||
listen, err := net.ListenTCP("tcp", tcpAddr)
|
||||
if err != nil {
|
||||
logx.Panic("get gateway tcp conn err:%v", err)
|
||||
}
|
||||
|
||||
gatewayServer := GetGatewayServer()
|
||||
server.ElegantExitServer(gatewayServer)
|
||||
|
||||
logx.Info("start gateway in addr: %s", tcpAddr.String())
|
||||
if err := gatewayServer.Serve(listen); err != nil {
|
||||
logx.Errorln(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
cobra.CheckErr(rootCmd.Execute())
|
||||
}
|
||||
|
||||
func GetGatewayServer() *grpc.Server {
|
||||
|
||||
targets := viper.GetStringSlice("gateway.target")
|
||||
|
||||
logx.Debug("service target in %v", targets)
|
||||
|
||||
stream := proxy.GetDirectorByServiceHash()
|
||||
endpoint := endpoint.NewHashEndpoint(endpoint.HashReplicasDefault, nil, targets...)
|
||||
|
||||
opts := make([]grpc.ServerOption, 0)
|
||||
opts = append(
|
||||
opts,
|
||||
grpc.ForceServerCodec(wheatCodec.Codec()),
|
||||
grpc.UnknownServiceHandler(proxy.TransparentHandler(stream, endpoint)),
|
||||
)
|
||||
|
||||
return grpc.NewServer(opts...)
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package codec
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc/encoding"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// protoCodec 用于 gateway 解析全部的 grpc 类型的消息
|
||||
type protoCodec struct{}
|
||||
|
||||
func (protoCodec) Name() string {
|
||||
return "wheat-cache-proto"
|
||||
}
|
||||
|
||||
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
return proto.Marshal(v.(proto.Message))
|
||||
}
|
||||
|
||||
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
return proto.Unmarshal(data, v.(proto.Message))
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
payload []byte
|
||||
}
|
||||
|
||||
type proxyCodec struct {
|
||||
baseCodec encoding.Codec
|
||||
}
|
||||
|
||||
func (p *proxyCodec) Name() string {
|
||||
return "wheat-cache-proxy"
|
||||
}
|
||||
|
||||
func (p *proxyCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
out, ok := v.(*Frame)
|
||||
if !ok {
|
||||
return p.Marshal(v)
|
||||
}
|
||||
return out.payload, nil
|
||||
}
|
||||
|
||||
func (p *proxyCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
dst, ok := v.(*Frame)
|
||||
if !ok {
|
||||
return p.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
dst.payload = data
|
||||
return nil
|
||||
}
|
||||
|
||||
// CodeWithParent 生成基于 proto 的解码器
|
||||
func CodeWithParent(parent encoding.Codec) encoding.Codec {
|
||||
return &proxyCodec{parent}
|
||||
}
|
||||
|
||||
func Codec() encoding.Codec {
|
||||
return CodeWithParent(protoCodec{})
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package endpoint
|
||||
|
||||
type EndpointInterface interface {
|
||||
GetTargetAddr(...string) (string, error)
|
||||
IsEmpty() bool
|
||||
AddTarget(targets ...string)
|
||||
}
|
||||
|
||||
const (
|
||||
HashReplicasDefault = 3
|
||||
)
|
|
@ -0,0 +1,85 @@
|
|||
package endpoint
|
||||
|
||||
import (
|
||||
"hash/crc32"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
||||
)
|
||||
|
||||
type HashFunc func(data []byte) uint32
|
||||
|
||||
// 实现 sort
|
||||
type UInt32Slice []uint32
|
||||
|
||||
func (s UInt32Slice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s UInt32Slice) Less(i, j int) bool {
|
||||
return s[i] < s[j]
|
||||
}
|
||||
|
||||
func (s UInt32Slice) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
type HashEndpoint struct {
|
||||
hash HashFunc
|
||||
replicas int // 复制因子
|
||||
keys UInt32Slice
|
||||
hashMap map[uint32]string // taraget 隐射
|
||||
}
|
||||
|
||||
func NewHashEndpoint(replicas int, fn HashFunc, target ...string) EndpointInterface {
|
||||
endpoint := &HashEndpoint{
|
||||
replicas: replicas,
|
||||
hash: fn,
|
||||
hashMap: make(map[uint32]string, len(target)),
|
||||
}
|
||||
|
||||
if endpoint.hash == nil {
|
||||
endpoint.hash = crc32.ChecksumIEEE // 默认使用 CRC32 算法
|
||||
}
|
||||
|
||||
endpoint.AddTarget(target...)
|
||||
|
||||
return endpoint
|
||||
}
|
||||
|
||||
func (h *HashEndpoint) IsEmpty() bool {
|
||||
return len(h.keys) == 0
|
||||
}
|
||||
|
||||
func (h *HashEndpoint) AddTarget(targets ...string) {
|
||||
for _, tar := range targets {
|
||||
|
||||
for i := 0; i < h.replicas; i++ {
|
||||
hash := h.hash([]byte(strconv.Itoa(i) + tar))
|
||||
h.keys = append(h.keys, hash)
|
||||
h.hashMap[hash] = tar
|
||||
}
|
||||
}
|
||||
|
||||
// 虚拟值排序,方便查找
|
||||
sort.Sort(h.keys)
|
||||
}
|
||||
|
||||
func (h *HashEndpoint) GetTargetAddr(str ...string) (string, error) {
|
||||
if h.IsEmpty() {
|
||||
return "", errorx.New("gateway not register transport")
|
||||
}
|
||||
|
||||
if len(str) != 1 {
|
||||
return "", errorx.New("must give key")
|
||||
|
||||
}
|
||||
hash := h.hash([]byte(str[0]))
|
||||
idx := sort.Search(len(h.keys), func(i int) bool { return h.keys[i] >= hash })
|
||||
if idx == len(h.keys) {
|
||||
return h.hashMap[h.keys[0]], nil
|
||||
}
|
||||
|
||||
return h.hashMap[h.keys[idx]], nil
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package endpoint
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestHashTransport_GetTargetAddr(t *testing.T) {
|
||||
tran := NewHashEndpoint(3, nil, "127.0.0.1:5581", "127.0.0.1:5582", "127.0.0.1:5583")
|
||||
|
||||
key := "test"
|
||||
|
||||
target, err := tran.GetTargetAddr(key)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, target, "127.0.0.1:5582")
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
import "gitee.com/wheat-os/wheatCache/gateway/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type StreamDirector func(ctx context.Context, fullMethodName string, endpoint endpoint.EndpointInterface) (context.Context, *grpc.ClientConn, error)
|
||||
|
||||
var (
|
||||
clientStreamDescForProxying = &grpc.StreamDesc{
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
}
|
||||
)
|
|
@ -0,0 +1,37 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/gateway/codec"
|
||||
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func GetDirectorByServiceHash() StreamDirector {
|
||||
return func(ctx context.Context, fullMethodName string, endpoint endpoint.EndpointInterface) (context.Context, *grpc.ClientConn, error) {
|
||||
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return nil, nil, status.Errorf(codes.Unknown, "from FromIncomingContext err")
|
||||
}
|
||||
|
||||
baseKey, ok := md[proto.BaseKeyMethodKey]
|
||||
if !ok {
|
||||
return nil, nil, status.Errorf(codes.Unknown,
|
||||
"grpc header is not found %s, please check the client interceptor", proto.BaseKeyMethodKey)
|
||||
}
|
||||
|
||||
target, err := endpoint.GetTargetAddr(baseKey...)
|
||||
if err != nil {
|
||||
return nil, nil, status.Errorf(codes.Unknown, "get transport err, err:%v", err)
|
||||
}
|
||||
|
||||
cli, err := grpc.DialContext(ctx, target, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.Codec())))
|
||||
return ctx, cli, err
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
wheatCodec "gitee.com/wheat-os/wheatCache/gateway/codec"
|
||||
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// TransparentHandler returns a handler that attempts to proxy all requests that are not registered in the server.
|
||||
// The indented use here is as a transparent proxy, where the server doesn't know about the services implemented by the
|
||||
// backends. It should be used as a `grpc.UnknownServiceHandler`.
|
||||
//
|
||||
// This can *only* be used if the `server` also uses grpcproxy.CodecForServer() ServerOption.
|
||||
func TransparentHandler(director StreamDirector, endpoint endpoint.EndpointInterface) grpc.StreamHandler {
|
||||
streamer := &handler{
|
||||
director,
|
||||
endpoint,
|
||||
}
|
||||
return streamer.handler
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
director StreamDirector
|
||||
endpoint endpoint.EndpointInterface
|
||||
}
|
||||
|
||||
// handler is where the real magic of proxying happens.
|
||||
// It is invoked like any gRPC server stream and uses the gRPC server framing to get and receive bytes from the wire,
|
||||
// forwarding it to a ClientStream established against the relevant ClientConn.
|
||||
func (s *handler) handler(srv interface{}, serverStream grpc.ServerStream) error {
|
||||
fullMethodName, ok := grpc.MethodFromServerStream(serverStream)
|
||||
if !ok {
|
||||
return status.Errorf(codes.Internal, "lowLevelServerStream not exists in context")
|
||||
}
|
||||
|
||||
outgoingCtx, backendConn, err := s.director(serverStream.Context(), fullMethodName, s.endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientCtx, clientCancel := context.WithCancel(outgoingCtx)
|
||||
defer clientCancel()
|
||||
|
||||
clientStream, err := grpc.NewClientStream(clientCtx, clientStreamDescForProxying, backendConn, fullMethodName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s2cErrChan := s.forwardServerToClient(serverStream, clientStream)
|
||||
c2sErrChan := s.forwardClientToServer(clientStream, serverStream)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case s2cErr := <-s2cErrChan:
|
||||
if s2cErr == io.EOF {
|
||||
// 客户端流发送完毕正常关闭结束, Proxy 关闭对 Backend 的连接
|
||||
clientStream.CloseSend()
|
||||
break
|
||||
}
|
||||
|
||||
clientCancel()
|
||||
return status.Errorf(codes.Internal, "failed proxying s2c: %v", s2cErr)
|
||||
case c2sErr := <-c2sErrChan:
|
||||
// 服务的没用在提供数据触发这个分支
|
||||
serverStream.SetTrailer(clientStream.Trailer())
|
||||
|
||||
if c2sErr != io.EOF {
|
||||
return c2sErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return status.Errorf(codes.Internal, "gRPC proxying should never reach this stage.")
|
||||
}
|
||||
|
||||
func (s *handler) forwardClientToServer(src grpc.ClientStream, dst grpc.ServerStream) chan error {
|
||||
ret := make(chan error, 1)
|
||||
go func() {
|
||||
f := &wheatCodec.Frame{}
|
||||
for i := 0; ; i++ {
|
||||
if err := src.RecvMsg(f); err != nil {
|
||||
ret <- err // this can be io.EOF which is happy case
|
||||
break
|
||||
}
|
||||
if i == 0 {
|
||||
// This is a bit of a hack, but client to server headers are only readable after first client msg is
|
||||
// received but must be written to server stream before the first msg is flushed.
|
||||
// This is the only place to do it nicely.
|
||||
md, err := src.Header()
|
||||
if err != nil {
|
||||
ret <- err
|
||||
break
|
||||
}
|
||||
if err := dst.SendHeader(md); err != nil {
|
||||
ret <- err
|
||||
break
|
||||
}
|
||||
}
|
||||
if err := dst.SendMsg(f); err != nil {
|
||||
ret <- err
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s *handler) forwardServerToClient(src grpc.ServerStream, dst grpc.ClientStream) chan error {
|
||||
ret := make(chan error, 1)
|
||||
go func() {
|
||||
f := &wheatCodec.Frame{}
|
||||
for i := 0; ; i++ {
|
||||
if err := src.RecvMsg(f); err != nil {
|
||||
ret <- err // this can be io.EOF which is happy case
|
||||
break
|
||||
}
|
||||
if err := dst.SendMsg(f); err != nil {
|
||||
ret <- err
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
return ret
|
||||
}
|
5
go.mod
|
@ -1,9 +1,12 @@
|
|||
module gitee.com/timedb/wheatCache
|
||||
module gitee.com/wheat-os/wheatCache
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/golang/mock v1.5.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
google.golang.org/grpc v1.41.0
|
||||
google.golang.org/protobuf v1.26.0
|
||||
)
|
||||
|
|
13
go.sum
|
@ -46,6 +46,7 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
|||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
|
@ -53,6 +54,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
|
@ -65,6 +67,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
|
@ -86,6 +89,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
@ -103,6 +107,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
|||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
@ -116,6 +121,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
|
@ -250,6 +256,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
|
@ -330,6 +337,7 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -462,6 +470,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
@ -532,6 +541,7 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D
|
|||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
|
@ -553,6 +563,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
|||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
|
||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -564,6 +576,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
|
|
58
makefile
|
@ -0,0 +1,58 @@
|
|||
BASE_PATH = $(shell pwd)
|
||||
STORAGE_PATH = $(BASE_PATH)/storage
|
||||
BASE_OUT = $(BASE_PATH)/bin
|
||||
|
||||
MAKEFLAGS+= --no-print-directory
|
||||
|
||||
dcgen:
|
||||
@python3 ./shell/gen_protobuf.py
|
||||
@python3 ./shell/proto.py
|
||||
@python3 ./shell/make-struct.py
|
||||
|
||||
.PHONY: build-storage
|
||||
build-storage:
|
||||
@cd storage && go build -o $(BASE_OUT)/storage
|
||||
|
||||
.PHONY: build-gateway
|
||||
build-gateway:
|
||||
@cd gateway && go build -o $(BASE_OUT)/gateway
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
@make gen-middleware
|
||||
@make build-storage
|
||||
@make build-gateway
|
||||
@sudo python3 ./shell/init_conf.py
|
||||
|
||||
.PHONY: storage
|
||||
storage:
|
||||
@./bin/storage storage
|
||||
|
||||
.PHONY: gateway
|
||||
gateway:
|
||||
@./bin/gateway gateway
|
||||
|
||||
.PHONY: gen-struct
|
||||
gen-struct:
|
||||
@python3 ./shell/make-struct.py
|
||||
|
||||
.PHONY: gen-protobuf
|
||||
gen-protobuf:
|
||||
@python3 ./shell/gen_protobuf.py
|
||||
|
||||
.PHONY: gen-middleware
|
||||
gen-middleware:
|
||||
@python3 ./shell/gen_middleware.py
|
||||
|
||||
.PHONY: init-conf
|
||||
init-conf:
|
||||
@python3 ./shell/init_conf.py
|
||||
|
||||
|
||||
.PHONY: gen-service
|
||||
gen-service:
|
||||
@python3 ./shell/make_service.py
|
||||
|
||||
.PHONY: gen-mock
|
||||
gen-mock:
|
||||
@mockgen -source=./pkg/proto/storage.pb.go CommServerClient > ./mock/storage/mock_client.gen.go
|
|
@ -0,0 +1,9 @@
|
|||
package errorx
|
||||
|
||||
func DaoTypeErr(typ string) error {
|
||||
return New("the type is not: %s", typ)
|
||||
}
|
||||
|
||||
func NotKeyErr(key string) error {
|
||||
return New("the key is not exist, key:%s", key)
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package errorx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// New TODO 添加链路追踪等 @bandl @lgq
|
||||
func New(msg string, format ...interface{}) error {
|
||||
msg = fmt.Sprintf(msg, format...)
|
||||
return errors.New(msg)
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package errorx
|
||||
|
||||
func EventRecoveryErr() error {
|
||||
return New("this event has been recycled")
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package errorx
|
||||
|
||||
func LruNotWorkFuncEventErr() error {
|
||||
return New("the event haven't work of function")
|
||||
}
|
||||
|
||||
func KeyBaseIsNilErr() error {
|
||||
return New("key base can't be nil")
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package errorx
|
||||
|
||||
func TimeOutErr() error {
|
||||
return New("time out err")
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package event
|
||||
|
||||
import "context"
|
||||
|
||||
type Consumer struct {
|
||||
driver DriverInterface
|
||||
}
|
||||
|
||||
func (c *Consumer) Receive(ctx context.Context) *event {
|
||||
return c.driver.Get()
|
||||
}
|
||||
|
||||
func (c *Consumer) NewEvent(name string) *event {
|
||||
return c.driver.NewEvent(name)
|
||||
}
|
||||
|
||||
func (c *Consumer) Recovery(e *event) {
|
||||
c.driver.Recovery(e)
|
||||
}
|
||||
|
||||
func NewConsumer(driver DriverInterface) ConsumerInterface {
|
||||
return &Consumer{
|
||||
driver: driver,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultEventState = int32(iota) //默认情况下的状态
|
||||
waitEventState // 等待状态
|
||||
workEventState //工作状态
|
||||
closeEventState //事件关闭状态
|
||||
)
|
||||
|
||||
type EventWorkFunc func() (interface{}, error)
|
||||
|
||||
type DriverInterface interface {
|
||||
Get() *event
|
||||
Put(*event)
|
||||
GetLength() int
|
||||
NewEvent(string) *event
|
||||
Recovery(*event)
|
||||
}
|
||||
|
||||
type ProduceInterface interface {
|
||||
Call(context.Context, *event)
|
||||
NewEvent(string) *event
|
||||
Recovery(*event)
|
||||
}
|
||||
|
||||
type ConsumerInterface interface {
|
||||
Receive(ctx context.Context) *event
|
||||
Recovery(*event)
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
package event
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
||||
)
|
||||
|
||||
// 事件 poll 降低 new 对象的频率
|
||||
type eventPoll struct {
|
||||
poll chan *event
|
||||
maxSize int32
|
||||
nowSize *int32
|
||||
}
|
||||
|
||||
func (e *eventPoll) getEvent() *event {
|
||||
issSize := atomic.LoadInt32(e.nowSize)
|
||||
if issSize < e.maxSize {
|
||||
atomic.AddInt32(e.nowSize, 1)
|
||||
return newEvent()
|
||||
}
|
||||
|
||||
return <-e.poll
|
||||
}
|
||||
|
||||
func (e *eventPoll) recovery(rEvent *event) {
|
||||
rEvent.Reset()
|
||||
e.poll <- rEvent
|
||||
}
|
||||
|
||||
func newEventPoll(maxSize int) *eventPoll {
|
||||
return &eventPoll{
|
||||
poll: make(chan *event, maxSize),
|
||||
maxSize: int32(maxSize),
|
||||
nowSize: new(int32),
|
||||
}
|
||||
}
|
||||
|
||||
type event struct {
|
||||
msgCtx map[string]interface{}
|
||||
eventName string
|
||||
msg map[string]string // 消息
|
||||
waitResult chan interface{} // 等待返回
|
||||
err error
|
||||
eventStatus *int32
|
||||
ttlManage *time.Timer
|
||||
}
|
||||
|
||||
func newEvent() *event {
|
||||
status := defaultEventState
|
||||
return &event{
|
||||
eventStatus: &status,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *event) Reset() {
|
||||
if e.ttlManage != nil {
|
||||
e.ttlManage.Stop()
|
||||
}
|
||||
|
||||
e.err = nil
|
||||
|
||||
atomic.SwapInt32(e.eventStatus, defaultEventState)
|
||||
}
|
||||
|
||||
func (e *event) SetMsg(key string, val string) {
|
||||
if e.msg == nil {
|
||||
e.msg = make(map[string]string)
|
||||
}
|
||||
e.msg[key] = val
|
||||
}
|
||||
|
||||
func (e *event) GetMsg(key string) string {
|
||||
return e.msg[key]
|
||||
}
|
||||
|
||||
func (e *event) GetEventName() string {
|
||||
return e.eventName
|
||||
}
|
||||
|
||||
// SetValue 写入 ctx 传递用参数
|
||||
func (e *event) SetValue(key string, value interface{}) {
|
||||
if e.msgCtx == nil {
|
||||
e.msgCtx = make(map[string]interface{})
|
||||
}
|
||||
e.msgCtx[key] = value
|
||||
}
|
||||
|
||||
func (e *event) GetValue(key string) (interface{}, bool) {
|
||||
val, ok := e.msgCtx[key]
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// InitWaitEvent 初始化 wait event 必须调用才拥有等待特性
|
||||
func (e *event) InitWaitEvent() {
|
||||
if e.waitResult == nil || len(e.waitResult) > 0 {
|
||||
e.waitResult = make(chan interface{})
|
||||
}
|
||||
|
||||
// 清理残留
|
||||
if e.ttlManage == nil {
|
||||
e.ttlManage = time.NewTimer(0)
|
||||
}
|
||||
e.ttlManage.Stop()
|
||||
if len(e.ttlManage.C) > 0 {
|
||||
<-e.ttlManage.C
|
||||
}
|
||||
|
||||
atomic.CompareAndSwapInt32(e.eventStatus, defaultEventState, waitEventState)
|
||||
}
|
||||
|
||||
// StartWaitEvent 开始一个等待任务
|
||||
func (e *event) StartWaitEvent(ttl time.Duration) (interface{}, error) {
|
||||
e.ttlManage.Reset(ttl)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-e.ttlManage.C:
|
||||
if atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, closeEventState) {
|
||||
return nil, errorx.TimeOutErr()
|
||||
}
|
||||
continue
|
||||
|
||||
case result := <-e.waitResult:
|
||||
atomic.CompareAndSwapInt32(e.eventStatus, workEventState, closeEventState)
|
||||
return result, e.err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *event) ExecWorkAndSendResult(work EventWorkFunc) (interface{}, error) {
|
||||
if !atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, workEventState) {
|
||||
return nil, errorx.New("not wait status, exec err")
|
||||
}
|
||||
|
||||
res, err := work()
|
||||
e.err = err
|
||||
e.waitResult <- res
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (e *event) SetResultErr(err error) {
|
||||
if !atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, workEventState) {
|
||||
return
|
||||
}
|
||||
|
||||
e.err = err
|
||||
e.waitResult <- nil
|
||||
}
|
||||
|
||||
type Driver struct {
|
||||
maxQueueSize int
|
||||
queue chan *event
|
||||
poll *eventPoll
|
||||
}
|
||||
|
||||
// Get 获取驱动
|
||||
func (d *Driver) Get() *event {
|
||||
return <-d.queue
|
||||
}
|
||||
|
||||
func (d *Driver) Put(event *event) {
|
||||
d.queue <- event
|
||||
}
|
||||
|
||||
func (d *Driver) GetLength() int {
|
||||
return len(d.queue)
|
||||
}
|
||||
|
||||
func (d *Driver) NewEvent(name string) *event {
|
||||
event := d.poll.getEvent()
|
||||
event.eventName = name
|
||||
return event
|
||||
}
|
||||
|
||||
// 任何时候回收事件都应该由 最后使用者回收
|
||||
func (d *Driver) Recovery(e *event) {
|
||||
d.poll.recovery(e)
|
||||
}
|
||||
|
||||
// NewDriver 新建 Driver
|
||||
func NewDriver(maxSize int) DriverInterface {
|
||||
return &Driver{
|
||||
maxQueueSize: maxSize,
|
||||
queue: make(chan *event, maxSize),
|
||||
poll: newEventPoll(maxSize),
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package event
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const testEvent = "1001"
|
||||
const waitTestEvent = "1002"
|
||||
|
||||
// 简单的 单向 event 使用
|
||||
func Test_EventDriver(t *testing.T) {
|
||||
driver := NewDriver(2000)
|
||||
produce := NewProduce(driver)
|
||||
consumer := NewConsumer(driver)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
wait := sync.WaitGroup{}
|
||||
wait.Add(30000)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 30000; i++ {
|
||||
event := produce.NewEvent(testEvent)
|
||||
event.SetMsg("k", strconv.Itoa(i))
|
||||
produce.Call(ctx, event)
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
event := consumer.Receive(ctx)
|
||||
fmt.Println(event.GetMsg("k"))
|
||||
consumer.Recovery(event)
|
||||
wait.Done()
|
||||
}
|
||||
}()
|
||||
|
||||
wait.Wait()
|
||||
|
||||
fmt.Println(*driver.(*Driver).poll.nowSize)
|
||||
}
|
||||
|
||||
// 双向 event
|
||||
func Test_WaitEventDriver(t *testing.T) {
|
||||
driver := NewDriver(200)
|
||||
produce := NewProduce(driver)
|
||||
consumer := NewConsumer(driver)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
wait := sync.WaitGroup{}
|
||||
wait.Add(300000)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 300000; i++ {
|
||||
event := produce.NewEvent(testEvent)
|
||||
event.SetMsg("k", strconv.Itoa(i))
|
||||
event.InitWaitEvent()
|
||||
produce.Call(ctx, event)
|
||||
val, err := event.StartWaitEvent(2 * time.Second)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(val)
|
||||
produce.Recovery(event)
|
||||
wait.Done()
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
event := consumer.Receive(ctx)
|
||||
event.ExecWorkAndSendResult(func() (interface{}, error) {
|
||||
msg := event.GetMsg("k")
|
||||
return "hello: " + msg, nil
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
wait.Wait()
|
||||
|
||||
fmt.Println(*driver.(*Driver).poll.nowSize)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package event
|
||||
|
||||
import "context"
|
||||
|
||||
type Produce struct {
|
||||
driver DriverInterface
|
||||
}
|
||||
|
||||
func (p *Produce) NewEvent(name string) *event {
|
||||
return p.driver.NewEvent(name)
|
||||
}
|
||||
|
||||
func (p *Produce) Recovery(e *event) {
|
||||
p.driver.Recovery(e)
|
||||
}
|
||||
|
||||
func (p *Produce) Call(ctx context.Context, e *event) {
|
||||
p.driver.Put(e)
|
||||
}
|
||||
|
||||
func NewProduce(driver DriverInterface) ProduceInterface {
|
||||
return &Produce{
|
||||
driver: driver,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package event2
|
||||
|
||||
import "context"
|
||||
|
||||
type Consumer struct {
|
||||
driver DriverInterface
|
||||
}
|
||||
|
||||
func (c *Consumer) Receive(ctx context.Context) *event {
|
||||
return c.driver.Get()
|
||||
}
|
||||
|
||||
func (c *Consumer) NewEvent(name string) *event {
|
||||
return c.driver.NewEvent(name)
|
||||
}
|
||||
|
||||
func NewConsumer(driver DriverInterface) ConsumerInterface {
|
||||
return &Consumer{
|
||||
driver: driver,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package event2
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const (
|
||||
initEventState = int32(iota) // 初始化状态
|
||||
waitEventState // 等待状态
|
||||
workEventState // 工作状态
|
||||
closeEventState // 事件关闭状态
|
||||
recoveryEventState // 事件回收状态
|
||||
)
|
||||
|
||||
const (
|
||||
awaitThread = 3
|
||||
)
|
||||
|
||||
const (
|
||||
WorkFuncEventKey = "workFunc"
|
||||
)
|
||||
|
||||
// 线程安全
|
||||
type EventWorkFunc func() (interface{}, error)
|
||||
|
||||
// 挂起事件, 线程不安全
|
||||
type EventAwaitFunc func() (interface{}, error)
|
||||
|
||||
// 实际操作
|
||||
type awaitFunc func() (*event, interface{}, error)
|
||||
|
||||
type DriverInterface interface {
|
||||
Get() *event
|
||||
Put(*event)
|
||||
GetLength() int
|
||||
NewEvent(string) *event
|
||||
|
||||
await(awaitFunc)
|
||||
recovery(e *event)
|
||||
}
|
||||
|
||||
type ProduceInterface interface {
|
||||
Call(context.Context, *event)
|
||||
NewEvent(string) *event
|
||||
}
|
||||
|
||||
type ConsumerInterface interface {
|
||||
Receive(ctx context.Context) *event
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
package event2
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
||||
)
|
||||
|
||||
type event struct {
|
||||
msgCtx map[string]interface{}
|
||||
eventName string
|
||||
msg map[string]string // 消息
|
||||
waitResult chan interface{} // 等待返回
|
||||
err error
|
||||
eventStatus int32
|
||||
ttlManage *time.Timer
|
||||
parentDriver DriverInterface
|
||||
}
|
||||
|
||||
func (e *event) reset() {
|
||||
if e.ttlManage != nil {
|
||||
e.ttlManage.Stop()
|
||||
|
||||
if len(e.ttlManage.C) > 0 {
|
||||
<-e.ttlManage.C
|
||||
}
|
||||
}
|
||||
|
||||
e.err = nil
|
||||
|
||||
// 清空结果
|
||||
if len(e.waitResult) != 0 {
|
||||
<-e.waitResult
|
||||
}
|
||||
}
|
||||
|
||||
func (e *event) Recovery() {
|
||||
e.parentDriver.recovery(e)
|
||||
}
|
||||
|
||||
func (e *event) SetMsg(key string, val string) {
|
||||
if e.msg == nil {
|
||||
e.msg = make(map[string]string)
|
||||
}
|
||||
e.msg[key] = val
|
||||
}
|
||||
|
||||
func (e *event) GetMsg(key string) string {
|
||||
if e.msg == nil {
|
||||
return ""
|
||||
}
|
||||
return e.msg[key]
|
||||
}
|
||||
|
||||
func (e *event) GetEventName() string {
|
||||
return e.eventName
|
||||
}
|
||||
|
||||
// SetValue 写入 ctx 传递用参数
|
||||
func (e *event) SetValue(key string, value interface{}) {
|
||||
if e.msgCtx == nil {
|
||||
e.msgCtx = make(map[string]interface{})
|
||||
}
|
||||
e.msgCtx[key] = value
|
||||
}
|
||||
|
||||
func (e *event) GetValue(key string) (interface{}, bool) {
|
||||
if e.msgCtx == nil {
|
||||
return nil, false
|
||||
}
|
||||
val, ok := e.msgCtx[key]
|
||||
return val, ok
|
||||
}
|
||||
|
||||
func (e *event) InitWaitEvent() {
|
||||
e.reset()
|
||||
if e.waitResult == nil {
|
||||
e.waitResult = make(chan interface{})
|
||||
}
|
||||
|
||||
atomic.SwapInt32(&e.eventStatus, waitEventState)
|
||||
}
|
||||
|
||||
func (e *event) SetResultErr(err error) {
|
||||
if !atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, workEventState) {
|
||||
return
|
||||
}
|
||||
|
||||
e.err = err
|
||||
e.waitResult <- nil
|
||||
}
|
||||
|
||||
// StartWaitEvent 开始一个等待任务
|
||||
func (e *event) StartWaitEvent(ttl time.Duration) (interface{}, error) {
|
||||
if e.ttlManage == nil {
|
||||
e.ttlManage = time.NewTimer(ttl)
|
||||
} else {
|
||||
e.ttlManage.Reset(ttl)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-e.ttlManage.C:
|
||||
if atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, closeEventState) {
|
||||
return nil, errorx.TimeOutErr()
|
||||
}
|
||||
continue
|
||||
|
||||
case result := <-e.waitResult:
|
||||
atomic.SwapInt32(&e.eventStatus, closeEventState)
|
||||
return result, e.err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 实际执行推送
|
||||
func (e *event) execWorker(res interface{}, err error) {
|
||||
switch work := res.(type) {
|
||||
case EventAwaitFunc:
|
||||
await := func() (*event, interface{}, error) {
|
||||
result, err := work()
|
||||
return e, result, err
|
||||
}
|
||||
e.parentDriver.await(await)
|
||||
|
||||
case EventWorkFunc:
|
||||
e.InitWaitEvent()
|
||||
e.SetValue(WorkFuncEventKey, work)
|
||||
e.parentDriver.Put(e)
|
||||
|
||||
default:
|
||||
e.err = err
|
||||
e.waitResult <- res
|
||||
}
|
||||
}
|
||||
|
||||
func (e *event) ExecWorkAndSendResult(work EventWorkFunc) (interface{}, error) {
|
||||
if !atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, workEventState) {
|
||||
return nil, errorx.New("not wait status, exec err")
|
||||
}
|
||||
|
||||
res, err := work()
|
||||
e.execWorker(res, err)
|
||||
return res, err
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
waitQueue chan awaitFunc
|
||||
eventQueue chan *event
|
||||
levelQueue chan *event
|
||||
|
||||
// event 池的实现
|
||||
poll chan *event
|
||||
maxPoolSize int32
|
||||
nowPoolSize int32
|
||||
}
|
||||
|
||||
func NewDriver(maxSize int) DriverInterface {
|
||||
d := &driver{
|
||||
// pool
|
||||
maxPoolSize: int32(maxSize),
|
||||
nowPoolSize: 0,
|
||||
poll: make(chan *event, maxSize),
|
||||
|
||||
// waitQueue 1/3 的挂起指标
|
||||
waitQueue: make(chan awaitFunc, maxSize/3),
|
||||
levelQueue: make(chan *event, maxSize/3),
|
||||
eventQueue: make(chan *event, maxSize),
|
||||
}
|
||||
d.awaitWorker()
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *driver) NewEvent(name string) *event {
|
||||
|
||||
issSize := atomic.LoadInt32(&d.nowPoolSize)
|
||||
if issSize < d.maxPoolSize {
|
||||
atomic.AddInt32(&d.nowPoolSize, 1)
|
||||
return d.newEvent(name)
|
||||
}
|
||||
e := <-d.poll
|
||||
e.eventName = name
|
||||
return e
|
||||
}
|
||||
|
||||
func (d *driver) newEvent(name string) *event {
|
||||
status := initEventState
|
||||
return &event{
|
||||
eventStatus: status,
|
||||
parentDriver: d,
|
||||
eventName: name,
|
||||
}
|
||||
}
|
||||
|
||||
// 先尝试 level
|
||||
func (d *driver) Get() *event {
|
||||
if len(d.levelQueue) > 0 {
|
||||
return <-d.levelQueue
|
||||
}
|
||||
return <-d.eventQueue
|
||||
}
|
||||
|
||||
func (d *driver) Put(e *event) {
|
||||
d.eventQueue <- e
|
||||
}
|
||||
|
||||
func (d *driver) GetLength() int {
|
||||
return len(d.eventQueue) + len(d.levelQueue)
|
||||
}
|
||||
|
||||
func (d *driver) recovery(e *event) {
|
||||
atomic.SwapInt32(&e.eventStatus, recoveryEventState)
|
||||
e.reset()
|
||||
d.poll <- e
|
||||
}
|
||||
|
||||
// 挂起操作相关
|
||||
func (d *driver) await(a awaitFunc) {
|
||||
d.waitQueue <- a
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package event2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const testEvent = "1001"
|
||||
const waitTestEvent = "1002"
|
||||
|
||||
// 简单的 单向 event 使用
|
||||
func Test_EventDriver(t *testing.T) {
|
||||
driver := NewDriver(2000)
|
||||
produce := NewProduce(driver)
|
||||
consumer := NewConsumer(driver)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
wait := sync.WaitGroup{}
|
||||
wait.Add(30000)
|
||||
|
||||
go func() {
|
||||
for i := 0; i < 30000; i++ {
|
||||
event := produce.NewEvent(testEvent)
|
||||
event.SetMsg("k", strconv.Itoa(i))
|
||||
produce.Call(ctx, event)
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
event := consumer.Receive(ctx)
|
||||
fmt.Println(event.GetMsg("k"))
|
||||
event.Recovery()
|
||||
wait.Done()
|
||||
}
|
||||
}()
|
||||
|
||||
wait.Wait()
|
||||
|
||||
}
|
||||
|
||||
// 双向 event
|
||||
func Test_EventDriver_Tow_way(t *testing.T) {
|
||||
|
||||
ctx := context.Background()
|
||||
driver := NewDriver(2000)
|
||||
produce := NewProduce(driver)
|
||||
consumer := NewConsumer(driver)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
event := consumer.Receive(ctx)
|
||||
work, ok := event.GetValue(WorkFuncEventKey)
|
||||
if !ok {
|
||||
panic("get work key err")
|
||||
}
|
||||
workFunc, ok := work.(EventWorkFunc)
|
||||
if !ok {
|
||||
panic("work func err")
|
||||
}
|
||||
_, err := event.ExecWorkAndSendResult(workFunc)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 一般的 two-way 模式
|
||||
for i := 0; i < 10000; i++ {
|
||||
event := produce.NewEvent(waitTestEvent)
|
||||
event.InitWaitEvent()
|
||||
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
|
||||
return i + 1, nil
|
||||
}))
|
||||
produce.Call(ctx, event)
|
||||
res, err := event.StartWaitEvent(2 * time.Second)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, res, i+1)
|
||||
event.Recovery()
|
||||
}
|
||||
|
||||
// 挂起模式,2 秒左右的执行时间
|
||||
group := sync.WaitGroup{}
|
||||
group.Add(5)
|
||||
for i := 0; i < 5; i++ {
|
||||
go func(i int) {
|
||||
event := produce.NewEvent(waitTestEvent)
|
||||
event.InitWaitEvent()
|
||||
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
|
||||
// 访问 await Work 来发起一个 异步请求操作
|
||||
return EventAwaitFunc(func() (interface{}, error) {
|
||||
time.Sleep(time.Second)
|
||||
return i + 1, nil
|
||||
}), nil
|
||||
}))
|
||||
produce.Call(ctx, event)
|
||||
res, err := event.StartWaitEvent(2 * time.Second)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, res, i+1)
|
||||
event.Recovery()
|
||||
group.Done()
|
||||
}(i)
|
||||
}
|
||||
|
||||
// 挂起成功不发生超时
|
||||
for i := 0; i < 10000; i++ {
|
||||
event := produce.NewEvent(waitTestEvent)
|
||||
event.InitWaitEvent()
|
||||
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
|
||||
return i + 1, nil
|
||||
}))
|
||||
produce.Call(ctx, event)
|
||||
res, err := event.StartWaitEvent(500 * time.Millisecond)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, res, i+1)
|
||||
event.Recovery()
|
||||
}
|
||||
|
||||
group.Wait()
|
||||
|
||||
// 挂起一个高延迟操作, 保证局部操作还在事件中
|
||||
group = sync.WaitGroup{}
|
||||
group.Add(5)
|
||||
for i := 0; i < 5; i++ {
|
||||
event := produce.NewEvent(waitTestEvent)
|
||||
event.InitWaitEvent()
|
||||
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
|
||||
return EventAwaitFunc(func() (interface{}, error) {
|
||||
// 返回值为 EventWorkFunc 时, 会重新加入末端队列
|
||||
return EventWorkFunc(func() (interface{}, error) {
|
||||
return i + 1, nil
|
||||
}), nil
|
||||
|
||||
}), nil
|
||||
}))
|
||||
produce.Call(ctx, event)
|
||||
res, err := event.StartWaitEvent(2 * time.Second)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, res, i+1)
|
||||
event.Recovery()
|
||||
group.Done()
|
||||
fmt.Println(i)
|
||||
}
|
||||
group.Wait()
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package event2
|
||||
|
||||
import "context"
|
||||
|
||||
type Produce struct {
|
||||
driver DriverInterface
|
||||
}
|
||||
|
||||
func (p *Produce) NewEvent(name string) *event {
|
||||
return p.driver.NewEvent(name)
|
||||
}
|
||||
|
||||
func (p *Produce) Call(ctx context.Context, e *event) {
|
||||
p.driver.Put(e)
|
||||
}
|
||||
|
||||
func NewProduce(driver DriverInterface) ProduceInterface {
|
||||
return &Produce{
|
||||
driver: driver,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package event2
|
||||
|
||||
func (d *driver) awaitWorker() {
|
||||
for i := 0; i < awaitThread; i++ {
|
||||
go func() {
|
||||
for {
|
||||
awaitFunc := <-d.waitQueue
|
||||
e, res, err := awaitFunc()
|
||||
e.execWorker(res, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package define
|
|
@ -0,0 +1,43 @@
|
|||
package logx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type LogLevelState int8
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
stath []string
|
||||
)
|
||||
|
||||
type upLogger struct {
|
||||
ctx context.Context
|
||||
produce event.ProduceInterface
|
||||
}
|
||||
|
||||
func init() {
|
||||
once.Do(func() {
|
||||
stath = viper.GetStringSlice("logPrint.stath")
|
||||
})
|
||||
}
|
||||
|
||||
type logInterface interface {
|
||||
Debug(format string, msg ...interface{})
|
||||
Info(format string, msg ...interface{})
|
||||
Warn(format string, msg ...interface{})
|
||||
Error(format string, msg ...interface{})
|
||||
Panic(format string, msg ...interface{})
|
||||
|
||||
Debugln(msg ...interface{})
|
||||
Infoln(msg ...interface{})
|
||||
Warnln(msg ...interface{})
|
||||
Errorln(msg ...interface{})
|
||||
Panicln(msg ...interface{})
|
||||
|
||||
Print(level string, format string, msg ...interface{})
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package logx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
||||
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
|
||||
)
|
||||
|
||||
func With(ctx context.Context, p event.ProduceInterface) *upLogger {
|
||||
return &upLogger{
|
||||
ctx: ctx,
|
||||
produce: p,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *upLogger) Debug(format string, msg ...interface{}) {
|
||||
l.Print("DEBUG", format, msg...)
|
||||
}
|
||||
|
||||
func (l *upLogger) Info(format string, msg ...interface{}) {
|
||||
l.Print("INFO", format, msg...)
|
||||
}
|
||||
|
||||
func (l *upLogger) Warn(format string, msg ...interface{}) {
|
||||
l.Print("WARN", format, msg...)
|
||||
}
|
||||
|
||||
func (l *upLogger) Error(format string, msg ...interface{}) {
|
||||
l.Print("ERROR", format, msg...)
|
||||
}
|
||||
|
||||
func (l *upLogger) Panic(format string, msg ...interface{}) {
|
||||
l.Print("ERROR", format, msg...)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
func (l *upLogger) Print(level string, format string, msg ...interface{}) {
|
||||
logPrint(4, level, format, msg...)
|
||||
sendMsg := &middleMsg.LogContext{
|
||||
Level: level,
|
||||
Data: time.Now(),
|
||||
Msg: fmt.Sprintf(format, msg...),
|
||||
Route: findPlace(4),
|
||||
}
|
||||
middleMsg.SendMiddleMsg(l.ctx, l.produce, sendMsg)
|
||||
}
|
||||
|
||||
func (l *upLogger) Debugln(msg ...interface{}) {
|
||||
l.Print("DEBUG", "%s", format(msg...))
|
||||
}
|
||||
|
||||
func (l *upLogger) Infoln(msg ...interface{}) {
|
||||
l.Print("INFO", "%s", format(msg...))
|
||||
}
|
||||
|
||||
func (l *upLogger) Warnln(msg ...interface{}) {
|
||||
l.Print("WARN", "%s", format(msg...))
|
||||
}
|
||||
|
||||
func (l *upLogger) Errorln(msg ...interface{}) {
|
||||
l.Print("ERROR", "%s", format(msg...))
|
||||
}
|
||||
|
||||
func (l *upLogger) Panicln(msg ...interface{}) {
|
||||
l.Print("ERROR", "%s", format(msg...))
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
func Debug(format string, msg ...interface{}) {
|
||||
logPrint(3, "DEBUG", format, msg...)
|
||||
}
|
||||
func Info(format string, msg ...interface{}) {
|
||||
logPrint(3, "INFO", format, msg...)
|
||||
}
|
||||
func Warn(format string, msg ...interface{}) {
|
||||
logPrint(3, "WARN", format, msg...)
|
||||
}
|
||||
func Error(format string, msg ...interface{}) {
|
||||
logPrint(3, "ERROR", format, msg...)
|
||||
}
|
||||
func Panic(format string, msg ...interface{}) {
|
||||
logPrint(3, "PANIC", format, msg...)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
func Debugln(msg ...interface{}) {
|
||||
logPrint(3, "DEBUG", "%s", format(msg...))
|
||||
}
|
||||
func Infoln(msg ...interface{}) {
|
||||
logPrint(3, "INFO", "%s", format(msg...))
|
||||
}
|
||||
func Warnln(msg ...interface{}) {
|
||||
logPrint(3, "WARN", "%s", format(msg...))
|
||||
}
|
||||
func Errorln(msg ...interface{}) {
|
||||
logPrint(3, "ERROR", "%s", format(msg...))
|
||||
}
|
||||
func Panicln(msg ...interface{}) {
|
||||
logPrint(3, "PANIC", "%s", format(msg...))
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
func logPrint(floor int, level string, format string, msg ...interface{}) {
|
||||
place := findPlace(floor)
|
||||
datetime := fmt.Sprintf("%s", time.Now())[0:19]
|
||||
|
||||
switch level {
|
||||
case "DEBUG":
|
||||
fmt.Printf("\033[1;37;40m")
|
||||
case "INFO":
|
||||
fmt.Printf("\033[1;32;40m")
|
||||
case "WARN":
|
||||
fmt.Printf("\033[1;33;40m")
|
||||
default:
|
||||
fmt.Printf("\033[1;31;40m")
|
||||
|
||||
}
|
||||
|
||||
//fmt.Println(level, datetime, fmt.Sprintf(format, msg...))
|
||||
fmt.Printf("%s\t%v\t%s\n", level, datetime, fmt.Sprintf(format, msg...))
|
||||
|
||||
for _, lv := range stath {
|
||||
if strings.ToUpper(lv) == strings.ToUpper(level) {
|
||||
fmt.Println(place)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findPlace(floor int) string {
|
||||
|
||||
var (
|
||||
place string
|
||||
i = floor
|
||||
)
|
||||
|
||||
for {
|
||||
_, file, line, _ := runtime.Caller(i)
|
||||
if line == 0 {
|
||||
break
|
||||
}
|
||||
i++
|
||||
place = fmt.Sprintf("%s:%d\n%s", file, line, place)
|
||||
}
|
||||
|
||||
return place
|
||||
}
|
||||
|
||||
func format(message ...interface{}) (context string) {
|
||||
for _, msg := range message {
|
||||
context = fmt.Sprintf("%s\t%v", context, msg)
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package logx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
||||
)
|
||||
|
||||
func TestStd(t *testing.T) {
|
||||
Info("%d%s", 11, "Info")
|
||||
Debug("%d%s", 11, "Debug")
|
||||
Warn("%d%s", 11, "Warn")
|
||||
Error("%d%s", 11, "Error")
|
||||
|
||||
Infoln(1321, "dwad", 0x9812933)
|
||||
Debugln(1321, "dwad", 0x9812933)
|
||||
Warnln(1321, "dwad", 0x9812933)
|
||||
Errorln(1321, "dwad", 0x9812933)
|
||||
|
||||
//Panic("%d%s", 11, "Panic")
|
||||
|
||||
logger := With(context.Background(),
|
||||
event.NewProduce(event.NewDriver(100)))
|
||||
|
||||
logger.Info("%d%s", 11, "Info")
|
||||
logger.Debug("%d%s", 11, "Debug")
|
||||
logger.Warn("%d%s", 11, "Warn")
|
||||
logger.Error("%d%s", 11, "Error")
|
||||
//logger.Panic("%d%s", 11, "Panic")
|
||||
|
||||
logger.Infoln(11, "Info")
|
||||
logger.Debugln(11, "Debug")
|
||||
logger.Warnln(11, "Warn")
|
||||
logger.Errorln(11, "Error")
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package lru
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/structure"
|
||||
)
|
||||
|
||||
type SingleWorkFunc func() interface{}
|
||||
|
||||
const (
|
||||
OptionEventName = "operateEvent"
|
||||
CleanEventName = "clearEvent"
|
||||
TtlEventName = "ttlEvent"
|
||||
)
|
||||
|
||||
var (
|
||||
lruCacheOnce sync.Once
|
||||
lruCache *SingleCache
|
||||
)
|
||||
|
||||
const (
|
||||
defaultLruMaxSize = 1 * 1024 * 1024 * 1024
|
||||
defaultLruClearSize = 0.5 * 1024 * 1024 * 1024
|
||||
defaultLruEventDriver = 2000
|
||||
)
|
||||
const (
|
||||
defaultWaitTime = 20 * time.Minute
|
||||
)
|
||||
|
||||
type CacheInterface interface {
|
||||
Del() error
|
||||
Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool)
|
||||
Add(key *proto.BaseKey, val structure.KeyBaseInterface) error
|
||||
UpdateLruSize(length structure.UpdateLength)
|
||||
DelByKey(key *proto.BaseKey) error
|
||||
DelToClearSize() error
|
||||
}
|
||||
|
||||
// TTL
|
||||
const (
|
||||
defaultDetachNum = 300
|
||||
defaultTtlMaxLevel = 18
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
package define
|
||||
|
||||
// define
|
|
@ -0,0 +1,225 @@
|
|||
package lru
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"sync/atomic"
|
||||
|
||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event2"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/middle"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/structure"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/util"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type keyBaseValue struct {
|
||||
key string
|
||||
val structure.KeyBaseInterface
|
||||
expire int64 // 过期时间戳
|
||||
}
|
||||
|
||||
type SingleCache struct {
|
||||
maxsize int64 //最大的长度
|
||||
clearSize int64 // 清理长度
|
||||
nowSize int64 // 现在的长度
|
||||
li *list.List
|
||||
lruMap map[string]*list.Element
|
||||
lruMaxDiverSize int
|
||||
lruTtlManage *lruTTl // 定时清理器
|
||||
|
||||
lruDriver event2.DriverInterface
|
||||
lruConsumer event2.ConsumerInterface
|
||||
lruCleanProduce event2.ProduceInterface // 发送清理事件
|
||||
|
||||
middleProduce event.ProduceInterface // 中间件驱动
|
||||
}
|
||||
|
||||
// UpdateLruSize 更新现在的长度
|
||||
func (lru *SingleCache) UpdateLruSize(length structure.UpdateLength) {
|
||||
atomic.AddInt64(&lru.nowSize, int64(length))
|
||||
}
|
||||
|
||||
func cacheInit() (int64, int64, int, int) {
|
||||
maxSize := viper.GetString("lruCache.maxSize")
|
||||
retMaxSize, maxErr := util.ParseSizeToBit(maxSize)
|
||||
if maxErr != nil {
|
||||
return 0, 0, 0, 0
|
||||
}
|
||||
if retMaxSize == 0 {
|
||||
retMaxSize = defaultLruMaxSize
|
||||
}
|
||||
|
||||
clearSize := viper.GetString("lruCache.clearSize")
|
||||
retClearSize, clearErr := util.ParseSizeToBit(clearSize)
|
||||
if clearErr != nil {
|
||||
return 0, 0, 0, 0
|
||||
}
|
||||
if retClearSize == 0 {
|
||||
retClearSize = defaultLruClearSize
|
||||
}
|
||||
|
||||
maxDriver := viper.GetInt("lruCache.eventDriverSize")
|
||||
if maxDriver == 0 {
|
||||
maxDriver = defaultLruEventDriver
|
||||
}
|
||||
|
||||
detachNum := viper.GetInt("lruCache.detachNum")
|
||||
if detachNum == 0 {
|
||||
detachNum = defaultDetachNum
|
||||
}
|
||||
|
||||
return retMaxSize, retClearSize, maxDriver, detachNum
|
||||
}
|
||||
|
||||
// NewLRUCache lru初始化
|
||||
func NewLRUCache() *SingleCache {
|
||||
maxSize, clearSize, maxDriverSize, detachNum := cacheInit()
|
||||
lruDriver := event2.NewDriver(maxDriverSize)
|
||||
lruCacheOnce.Do(func() {
|
||||
lru := &SingleCache{
|
||||
maxsize: maxSize,
|
||||
clearSize: clearSize,
|
||||
nowSize: 0,
|
||||
li: list.New(),
|
||||
lruMap: make(map[string]*list.Element),
|
||||
lruMaxDiverSize: maxDriverSize,
|
||||
lruDriver: lruDriver,
|
||||
lruConsumer: event2.NewConsumer(lruDriver),
|
||||
lruCleanProduce: event2.NewProduce(lruDriver),
|
||||
middleProduce: event.NewProduce(middle.NewMiddleWare().GetEventDriver()),
|
||||
lruTtlManage: newLruTTl(detachNum),
|
||||
}
|
||||
lruCache = lru
|
||||
|
||||
// 启动 lru 事件驱动
|
||||
go lru.lruSingleWork()
|
||||
go lru.lruTtlWork()
|
||||
go lru.cleanWork()
|
||||
|
||||
})
|
||||
return lruCache
|
||||
}
|
||||
|
||||
// GetDriver 获取驱动
|
||||
func (lru *SingleCache) GetDriver() event2.DriverInterface {
|
||||
return lru.lruDriver
|
||||
}
|
||||
|
||||
//Add 增加
|
||||
func (lru *SingleCache) Add(key *proto.BaseKey, val structure.KeyBaseInterface) error {
|
||||
|
||||
if key == nil {
|
||||
return errorx.KeyBaseIsNilErr()
|
||||
}
|
||||
|
||||
exp := lru.lruTtlManage.setKeys(key)
|
||||
keyBaseVal := &keyBaseValue{
|
||||
key: key.Key,
|
||||
val: val,
|
||||
expire: exp,
|
||||
}
|
||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
||||
lru.li.MoveToFront(elVal)
|
||||
oldSize := elVal.Value.(structure.KeyBaseInterface).SizeByte()
|
||||
|
||||
lru.UpdateLruSize(structure.UpdateLength(val.SizeByte() - oldSize))
|
||||
elVal.Value = keyBaseVal
|
||||
return nil
|
||||
}
|
||||
valEl := lru.li.PushFront(keyBaseVal)
|
||||
lru.lruMap[key.Key] = valEl
|
||||
//增加大小
|
||||
lru.UpdateLruSize(structure.UpdateLength(valEl.Value.(*keyBaseValue).val.SizeByte()))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get 查找key对应的value
|
||||
func (lru *SingleCache) Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool) {
|
||||
|
||||
if key == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
||||
lru.li.MoveToFront(elVal)
|
||||
return elVal.Value.(*keyBaseValue).val, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
//Del 删除机制
|
||||
func (lru *SingleCache) Del() error {
|
||||
if lru.lruMap == nil {
|
||||
return errorx.New("lru is nil")
|
||||
}
|
||||
data := lru.li.Back()
|
||||
delete(lru.lruMap, data.Value.(*keyBaseValue).key)
|
||||
//删除大小
|
||||
lru.UpdateLruSize(structure.UpdateLength(-1 * data.Value.(*keyBaseValue).val.SizeByte()))
|
||||
lru.li.Remove(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
//DelByKey 根据key删除
|
||||
func (lru *SingleCache) DelByKey(key *proto.BaseKey) error {
|
||||
|
||||
if key == nil {
|
||||
return errorx.KeyBaseIsNilErr()
|
||||
}
|
||||
|
||||
if lru.lruMap == nil {
|
||||
return errorx.New("lru is nil")
|
||||
}
|
||||
if el, ok := lru.lruMap[key.Key]; ok {
|
||||
delete(lru.lruMap, key.Key)
|
||||
lru.li.Remove(el)
|
||||
lru.UpdateLruSize(structure.UpdateLength(-1 * el.Value.(*keyBaseValue).val.SizeByte()))
|
||||
return nil
|
||||
}
|
||||
return errorx.New("lru no this key")
|
||||
}
|
||||
|
||||
//DelByKeyAndExTtl 根据key(string)删除已经过期的 key
|
||||
func (lru *SingleCache) delByKeyAndExTtl(key string, beforeTime int64) {
|
||||
if elVal, ok := lru.lruMap[key]; ok {
|
||||
exp := elVal.Value.(*keyBaseValue).expire
|
||||
if exp <= beforeTime {
|
||||
delete(lru.lruMap, key)
|
||||
lru.li.Remove(elVal)
|
||||
lru.UpdateLruSize(structure.UpdateLength(-1 * elVal.Value.(*keyBaseValue).val.SizeByte()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (lru *SingleCache) DelToClearSize() error {
|
||||
if lru.lruMap == nil {
|
||||
return errorx.New("lru is nil")
|
||||
}
|
||||
for lru.nowSize > lru.clearSize {
|
||||
//del自动给nowSize进行大小的改变
|
||||
err := lru.Del()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新过期时间
|
||||
func (lru *SingleCache) UpdateTTl(key *proto.BaseKey) error {
|
||||
|
||||
if key == nil {
|
||||
return errorx.KeyBaseIsNilErr()
|
||||
}
|
||||
|
||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
||||
expire := lru.lruTtlManage.setKeys(key)
|
||||
elVal.Value.(*keyBaseValue).expire = expire
|
||||
}
|
||||
|
||||
return errorx.New("the key is not in lru cache, key:%s", key.Key)
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package lru
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewLRUCache(t *testing.T) {
|
||||
cache := NewLRUCache()
|
||||
v1 := stringx.NewStringSingle()
|
||||
v2 := stringx.NewStringSingle()
|
||||
v3 := stringx.NewStringSingle()
|
||||
key1 := proto.BaseKey{
|
||||
Key: "1",
|
||||
}
|
||||
key2 := proto.BaseKey{
|
||||
Key: "2",
|
||||
}
|
||||
key3 := proto.BaseKey{
|
||||
Key: "3",
|
||||
}
|
||||
cache.Add(&key1, v1)
|
||||
cache.Add(&key2, v2)
|
||||
cache.Add(&key3, v3)
|
||||
cache.Add(&key1, v1)
|
||||
fmt.Println(cache.nowSize)
|
||||
cache.Del()
|
||||
fmt.Println(cache.nowSize)
|
||||
_, isTrue := cache.Get(&key1)
|
||||
require.Equal(t, isTrue, true)
|
||||
}
|
||||
|
||||
func TestNewLRUCache2(t *testing.T) {
|
||||
//根据key删除
|
||||
cache := NewLRUCache()
|
||||
v1 := stringx.NewStringSingle()
|
||||
v2 := stringx.NewStringSingle()
|
||||
v3 := stringx.NewStringSingle()
|
||||
key1 := proto.BaseKey{
|
||||
Key: "1",
|
||||
}
|
||||
key2 := proto.BaseKey{
|
||||
Key: "2",
|
||||
}
|
||||
key3 := proto.BaseKey{
|
||||
Key: "3",
|
||||
}
|
||||
cache.Add(&key1, v1)
|
||||
cache.Add(&key2, v2)
|
||||
cache.Add(&key3, v3)
|
||||
cache.DelByKey(&key1)
|
||||
_, ok := cache.Get(&key1)
|
||||
require.Equal(t, ok, false)
|
||||
require.Error(t, cache.DelByKey(&key1))
|
||||
}
|
||||
|
||||
func TestLruProcess(t *testing.T) {
|
||||
lru := NewLRUCache()
|
||||
lru.clearSize = 3600
|
||||
|
||||
for i := 100; i < 200; i++ {
|
||||
lru.Add(&proto.BaseKey{
|
||||
Key: fmt.Sprint(i),
|
||||
Ttl: 20 << 2,
|
||||
}, stringx.NewStringSingle())
|
||||
}
|
||||
|
||||
// mock LruKey
|
||||
for i := 0; i < 100; i++ {
|
||||
lru.Add(&proto.BaseKey{
|
||||
Key: fmt.Sprint(i),
|
||||
Ttl: 4,
|
||||
}, stringx.NewStringSingle())
|
||||
}
|
||||
|
||||
require.Equal(t, lru.nowSize, int64(200*24))
|
||||
|
||||
// 自动清理测试
|
||||
fmt.Println(lru.clearSize)
|
||||
require.Equal(t, lru.li.Len(), 200)
|
||||
time.Sleep(3 * time.Second)
|
||||
require.Less(t, lru.nowSize, lru.clearSize+1)
|
||||
|
||||
// TTL 测试, 100-200 key 发生自动清理 留下 50-100 共 100(0-100) + 20个 key,5s 后,前 0-100的 key 过期,剩下
|
||||
time.Sleep(2 * time.Second)
|
||||
require.Equal(t, lru.li.Len(), 50)
|
||||
|
||||
// 过期全部的 Key
|
||||
for i := 100; i < 200; i++ {
|
||||
lru.UpdateTTl(&proto.BaseKey{
|
||||
Key: fmt.Sprint(i),
|
||||
Ttl: -1,
|
||||
})
|
||||
}
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
require.Equal(t, lru.nowSize, int64(0))
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package lru
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/util/skiplist"
|
||||
)
|
||||
|
||||
// lru 的 ttl 管理器
|
||||
type lruTTl struct {
|
||||
sk *skiplist.SkipList
|
||||
memoryKey chan string // 缓存过期的 key
|
||||
detachNum int // 每次移除的数量
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (l *lruTTl) setKeys(key *proto.BaseKey) int64 {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
// 永久存储
|
||||
if key.Expire == nil && key.Ttl == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
ttlTime := time.Now().Unix()
|
||||
if key.Expire != nil {
|
||||
ttlTime = key.Expire.GetSeconds()
|
||||
}
|
||||
|
||||
ttlTime += key.GetTtl()
|
||||
l.sk.Insert(float64(ttlTime), key.GetKey())
|
||||
|
||||
return ttlTime
|
||||
}
|
||||
|
||||
// 加载过期的 Key 到 Memory
|
||||
func (l *lruTTl) ttlKeyToMemoryBySecond() {
|
||||
t := time.Now()
|
||||
values := l.sk.PopLeft(float64(t.Unix()))
|
||||
|
||||
for _, val := range values {
|
||||
l.memoryKey <- val.(string)
|
||||
}
|
||||
}
|
||||
|
||||
func newLruTTl(detachNum int) *lruTTl {
|
||||
return &lruTTl{
|
||||
sk: skiplist.NewSkipList(defaultTtlMaxLevel),
|
||||
// 默认 10000 个 Key
|
||||
memoryKey: make(chan string, 10000),
|
||||
detachNum: detachNum,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package lru
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTTlCup(t *testing.T) {
|
||||
k := make([]string, 100, 3000)
|
||||
fmt.Println(cap(k))
|
||||
p := k[:50]
|
||||
fmt.Println(cap(p))
|
||||
}
|
||||
|
||||
func Test_LruTTl(t *testing.T) {
|
||||
lru := NewLRUCache()
|
||||
s := stringx.NewStringSingle()
|
||||
lru.Add(&proto.BaseKey{
|
||||
Key: "k8s",
|
||||
Ttl: 1,
|
||||
}, s)
|
||||
lru.Add(&proto.BaseKey{
|
||||
Key: "990",
|
||||
Ttl: 10,
|
||||
}, s)
|
||||
require.Equal(t, lru.nowSize, int64(48))
|
||||
|
||||
time.Sleep(4 * time.Second)
|
||||
require.Equal(t, lru.nowSize, int64(24))
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package lru
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event2"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/logx"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestWorker(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
lru := NewLRUCache()
|
||||
produce := event2.NewProduce(lru.GetDriver())
|
||||
workEvent := produce.NewEvent(OptionEventName)
|
||||
workEvent.SetValue(event2.WorkFuncEventKey, event2.EventWorkFunc(func() (interface{}, error) {
|
||||
v1 := stringx.NewStringSingle()
|
||||
key := proto.BaseKey{
|
||||
Key: "v1",
|
||||
}
|
||||
res, _ := v1.Set("123")
|
||||
lru.Add(&key, v1)
|
||||
return res, nil
|
||||
}))
|
||||
workEvent.InitWaitEvent()
|
||||
produce.Call(ctx, workEvent)
|
||||
res, err := workEvent.StartWaitEvent(2 * time.Second)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, res, "123")
|
||||
}
|
||||
|
||||
func TestSingleCache_DelToClearSize(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
lru := NewLRUCache()
|
||||
produce := event2.NewProduce(lru.GetDriver())
|
||||
|
||||
for i := int32(20000); i > 0; i-- {
|
||||
workEvent := produce.NewEvent(OptionEventName)
|
||||
workEvent.SetValue(event2.WorkFuncEventKey, event2.EventWorkFunc(func() (interface{}, error) {
|
||||
v1 := stringx.NewStringSingle()
|
||||
key := proto.BaseKey{
|
||||
Key: string(i),
|
||||
Ttl: 1,
|
||||
}
|
||||
u := v1.Setbit(i, true)
|
||||
lru.Add(&key, v1)
|
||||
return u, nil
|
||||
}))
|
||||
workEvent.InitWaitEvent()
|
||||
produce.Call(ctx, workEvent)
|
||||
workEvent.StartWaitEvent(2 * time.Second)
|
||||
workEvent.Recovery()
|
||||
}
|
||||
|
||||
logx.Info("start size is %d", lru.nowSize)
|
||||
time.Sleep(10 * time.Second)
|
||||
logx.Info("end size is %d", lru.nowSize)
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
package lru
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event2"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/logx"
|
||||
mMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
|
||||
)
|
||||
|
||||
func (lru *SingleCache) lruSingleWork() {
|
||||
ctx := context.Background()
|
||||
for {
|
||||
workEvent := lru.lruConsumer.Receive(ctx)
|
||||
workFunc, ok := workEvent.GetValue(event2.WorkFuncEventKey)
|
||||
if !ok {
|
||||
workEvent.SetResultErr(errorx.LruNotWorkFuncEventErr())
|
||||
continue
|
||||
}
|
||||
|
||||
switch workEvent.GetEventName() {
|
||||
case OptionEventName:
|
||||
if work, ok := workFunc.(event2.EventWorkFunc); ok {
|
||||
workEvent.ExecWorkAndSendResult(work)
|
||||
}
|
||||
|
||||
case CleanEventName:
|
||||
// 对当前的io数量进行判断
|
||||
ioNum := lru.GetDriver().GetLength()
|
||||
if ioNum > lru.lruMaxDiverSize/2 {
|
||||
lru.lruCleanProduce.Call(ctx, workEvent)
|
||||
continue
|
||||
}
|
||||
if work, ok := workFunc.(event2.EventWorkFunc); ok {
|
||||
workEvent.ExecWorkAndSendResult(work)
|
||||
}
|
||||
|
||||
case TtlEventName:
|
||||
if work, ok := workFunc.(event2.EventWorkFunc); ok {
|
||||
workEvent.ExecWorkAndSendResult(work)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行过期事件
|
||||
func (lru *SingleCache) lruTtlWork() {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 清理事件
|
||||
go func() {
|
||||
work := event2.EventWorkFunc(func() (interface{}, error) {
|
||||
|
||||
beforeTime := time.Now().Unix()
|
||||
cle := lru.lruTtlManage.detachNum
|
||||
if cle > len(lru.lruTtlManage.memoryKey) {
|
||||
cle = len(lru.lruTtlManage.memoryKey)
|
||||
}
|
||||
|
||||
keys := make([]string, 0)
|
||||
for i := 0; i < cle; i++ {
|
||||
key := <-lru.lruTtlManage.memoryKey
|
||||
keys = append(keys, key)
|
||||
lru.delByKeyAndExTtl(key, beforeTime)
|
||||
}
|
||||
return keys, nil
|
||||
})
|
||||
|
||||
cleanTTlTicker := time.NewTicker(500 * time.Millisecond)
|
||||
defer cleanTTlTicker.Stop()
|
||||
|
||||
for {
|
||||
// 清理事件
|
||||
<-cleanTTlTicker.C
|
||||
if len(lru.lruTtlManage.memoryKey) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
ttlEvent := lru.lruCleanProduce.NewEvent(TtlEventName)
|
||||
ttlEvent.SetValue(event2.WorkFuncEventKey, work)
|
||||
ttlEvent.InitWaitEvent()
|
||||
|
||||
lru.lruCleanProduce.Call(ctx, ttlEvent)
|
||||
keys, err := ttlEvent.StartWaitEvent(time.Second * 2)
|
||||
ttlEvent.Recovery()
|
||||
|
||||
mMsg.SendMiddleMsg(ctx, lru.middleProduce, mMsg.LruTTlContext{
|
||||
Keys: keys.([]string),
|
||||
CleanTime: time.Now(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logx.With(ctx, lru.middleProduce).Errorln(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 收集事件
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
lru.lruTtlManage.ttlKeyToMemoryBySecond()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (lru *SingleCache) cleanWork() {
|
||||
cxt := context.Background()
|
||||
work := event.EventWorkFunc(func() (interface{}, error) {
|
||||
err := lru.DelToClearSize()
|
||||
return nil, err
|
||||
})
|
||||
|
||||
for {
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
if lru.clearSize < lru.nowSize {
|
||||
lruCleanEvent := lru.lruCleanProduce.NewEvent(CleanEventName)
|
||||
lruCleanEvent.SetValue(event2.WorkFuncEventKey, work)
|
||||
|
||||
lruCleanEvent.InitWaitEvent()
|
||||
lru.lruCleanProduce.Call(cxt, lruCleanEvent)
|
||||
_, err := lruCleanEvent.StartWaitEvent(defaultWaitTime)
|
||||
if err != nil {
|
||||
logx.With(cxt, lru.middleProduce).Errorln(err)
|
||||
}
|
||||
|
||||
// 归还
|
||||
lruCleanEvent.Recovery()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package middlemsg
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
||||
)
|
||||
|
||||
const (
|
||||
MiddleMsgKey = "middleMsgKey"
|
||||
)
|
||||
|
||||
func SendMiddleMsg(
|
||||
ctx context.Context,
|
||||
middleProduce event.ProduceInterface,
|
||||
val interface{},
|
||||
) error {
|
||||
if middleProduce == nil {
|
||||
return errorx.New("middleProduce not is nil")
|
||||
}
|
||||
|
||||
var eventName string
|
||||
|
||||
switch val.(type) {
|
||||
case *LogContext:
|
||||
eventName = LogContextName
|
||||
case *LruCleanContext:
|
||||
eventName = LruCleanContextName
|
||||
case *LruTTlContext:
|
||||
eventName = LruTTlContextName
|
||||
case *PulginsInfos:
|
||||
eventName = PulginsInfosName
|
||||
}
|
||||
|
||||
msgEvent := middleProduce.NewEvent(eventName)
|
||||
msgEvent.SetValue(MiddleMsgKey, val)
|
||||
middleProduce.Call(ctx, msgEvent)
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package middlemsg
|
||||
|
||||
import "time"
|
||||
|
||||
var (
|
||||
LogContextName = "log-context"
|
||||
)
|
||||
|
||||
type LogContext struct {
|
||||
Level string
|
||||
Data time.Time
|
||||
Msg string
|
||||
Route string
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package middlemsg
|
||||
|
||||
import "time"
|
||||
|
||||
const LruCleanContextName = "lru-clean-context"
|
||||
|
||||
type LruCleanContext struct {
|
||||
Keys []string
|
||||
BeforeCleanSize int64
|
||||
BehindCleanSize int64
|
||||
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
}
|
||||
|
||||
const LruTTlContextName = "lru-ttl-context"
|
||||
|
||||
type LruTTlContext struct {
|
||||
Keys []string
|
||||
CleanTime time.Time
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package middlemsg
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
PulginsInfosName = "plugins-infos-context"
|
||||
)
|
||||
|
||||
type PulginsInfo struct {
|
||||
Version string
|
||||
Desc string
|
||||
Name string
|
||||
Statux string
|
||||
Time time.Duration
|
||||
}
|
||||
|
||||
type PulginsInfos struct {
|
||||
Infos []*PulginsInfo
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package middle
|
||||
|
||||
// 数据类型
|
||||
type data struct {
|
||||
m map[string]interface{}
|
||||
}
|
||||
|
||||
// 数据初始化,分配内存
|
||||
func NewData() *data {
|
||||
return &data{
|
||||
make(map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
func (d *data) Get(key string) interface{} {
|
||||
return d.m[key]
|
||||
}
|
||||
|
||||
// 推入数据
|
||||
func (d *data) Put(key string, val interface{}) error {
|
||||
d.m[key] = val
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package middle
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
oneMiddle sync.Once
|
||||
middleWareDriver *MiddleWare
|
||||
)
|
||||
|
||||
const (
|
||||
defaultConsumerCount = 5
|
||||
defaultDriverCount = 1000
|
||||
)
|
|
@ -1,62 +0,0 @@
|
|||
package middle
|
||||
|
||||
// 获取数据的接口
|
||||
type Msg interface {
|
||||
Put(key string, val interface{}) error
|
||||
Get(key string) interface{}
|
||||
}
|
||||
|
||||
type middleWare interface {
|
||||
Put(msg Msg)
|
||||
Out() Msg
|
||||
}
|
||||
|
||||
type MiddlewareConf struct {
|
||||
Weight int
|
||||
Middle middleWare
|
||||
}
|
||||
|
||||
type Driver struct {
|
||||
conf []*MiddlewareConf
|
||||
}
|
||||
|
||||
func NewDriver() *Driver {
|
||||
return new(Driver)
|
||||
}
|
||||
|
||||
// 驱动
|
||||
func (d *Driver) Start(msg Msg) {
|
||||
|
||||
for _, m := range d.conf {
|
||||
|
||||
go m.Middle.Put(msg)
|
||||
|
||||
msg = m.Middle.Out()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
conf := []*MiddlewareConf{
|
||||
{
|
||||
Weight: 1,
|
||||
Middle: NewUpload(),
|
||||
},
|
||||
{
|
||||
Weight: 2,
|
||||
Middle: NewStorage(),
|
||||
},
|
||||
{
|
||||
Weight: 3,
|
||||
Middle: NewSend(),
|
||||
},
|
||||
}
|
||||
|
||||
da := NewDriver()
|
||||
da.conf = conf
|
||||
val := NewData()
|
||||
val.Put("200", 2)
|
||||
|
||||
da.Start(val)
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package middle
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestMiddle(t *testing.T) {
|
||||
main()
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package middle
|
||||
|
||||
import (
|
||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
||||
"gitee.com/wheat-os/wheatCache/plugins"
|
||||
"gitee.com/wheat-os/wheatCache/plugins/config"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type MiddleWare struct {
|
||||
eventDriver event.DriverInterface
|
||||
eventConsumer event.ConsumerInterface
|
||||
eventProduce event.ProduceInterface
|
||||
plugins map[string][]plugins.PluginInterface
|
||||
consumerCount int
|
||||
driverCount int
|
||||
}
|
||||
|
||||
func NewMiddleWare() *MiddleWare {
|
||||
oneMiddle.Do(func() {
|
||||
consumerCount, driverCount := loadConfigAndDefault()
|
||||
|
||||
driver := event.NewDriver(driverCount)
|
||||
middleWareDriver = &MiddleWare{
|
||||
eventDriver: driver,
|
||||
eventConsumer: event.NewConsumer(driver),
|
||||
eventProduce: event.NewProduce(driver),
|
||||
driverCount: driverCount,
|
||||
consumerCount: consumerCount,
|
||||
}
|
||||
middleWareDriver.loadPlugins()
|
||||
|
||||
// 多消费 middle
|
||||
middleWareDriver.startWork()
|
||||
})
|
||||
return middleWareDriver
|
||||
}
|
||||
|
||||
func (m *MiddleWare) GetEventDriver() event.DriverInterface {
|
||||
return m.eventDriver
|
||||
}
|
||||
|
||||
func (m *MiddleWare) loadPlugins() {
|
||||
plug := viper.GetStringMapStringSlice("plugins-control")
|
||||
|
||||
pluginsMap := config.GetMiddlewareMap()
|
||||
|
||||
pluginsContext := make(map[string][]plugins.PluginInterface)
|
||||
|
||||
for msg, pluNames := range plug {
|
||||
pulgSingle := make([]plugins.PluginInterface, 0)
|
||||
for _, name := range pluNames {
|
||||
pulgSingle = append(pulgSingle, pluginsMap[name])
|
||||
}
|
||||
|
||||
pluginsContext[msg] = pulgSingle
|
||||
}
|
||||
|
||||
m.plugins = pluginsContext
|
||||
}
|
||||
|
||||
func loadConfigAndDefault() (int, int) {
|
||||
// 加载 consumerCount
|
||||
consumerCount := viper.GetInt("middle-driver.middleConsumerCount")
|
||||
if consumerCount == 0 {
|
||||
consumerCount = defaultConsumerCount
|
||||
}
|
||||
driverCount := viper.GetInt("middle-driver.driverCount")
|
||||
if driverCount == 0 {
|
||||
driverCount = defaultDriverCount
|
||||
}
|
||||
return consumerCount, driverCount
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package middle
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Send struct {
|
||||
ch chan *data
|
||||
}
|
||||
|
||||
func NewSend() *Send {
|
||||
return &Send{
|
||||
make(chan *data),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Send) Put(msg Msg) {
|
||||
da := NewData()
|
||||
da.Put("1", msg)
|
||||
fmt.Println("传入Send")
|
||||
m.ch <- da
|
||||
}
|
||||
|
||||
func (m *Send) Out() Msg {
|
||||
return <-m.ch
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package middle
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Storage struct {
|
||||
ch chan *data
|
||||
}
|
||||
|
||||
func NewStorage() *Storage {
|
||||
return &Storage{
|
||||
make(chan *data),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Storage) Put(msg Msg) {
|
||||
da := NewData()
|
||||
da.Put("1", msg)
|
||||
fmt.Println("传入Storage")
|
||||
m.ch <- da
|
||||
}
|
||||
|
||||
func (m *Storage) Out() Msg {
|
||||
return <-m.ch
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package middle
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Upload struct {
|
||||
ch chan *data
|
||||
}
|
||||
|
||||
func NewUpload() *Upload {
|
||||
return &Upload{
|
||||
make(chan *data),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Upload) Put(msg Msg) {
|
||||
da := NewData()
|
||||
da.Put("1", msg)
|
||||
fmt.Println("传入Upload")
|
||||
|
||||
m.ch <- da
|
||||
}
|
||||
|
||||
func (m *Upload) Out() Msg {
|
||||
return <-m.ch
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package middle
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/logx"
|
||||
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
|
||||
)
|
||||
|
||||
func (m *MiddleWare) startWork() {
|
||||
|
||||
for i := 0; i < m.consumerCount; i++ {
|
||||
go func() {
|
||||
ctx := context.Background()
|
||||
for {
|
||||
workEvent := m.eventConsumer.Receive(ctx)
|
||||
plugs := m.plugins[workEvent.GetEventName()]
|
||||
msg, ok := workEvent.GetValue(middleMsg.MiddleMsgKey)
|
||||
m.eventConsumer.Recovery(workEvent)
|
||||
|
||||
if !ok {
|
||||
logx.With(ctx, m.eventProduce).Error("get event value err,not key:%s", middleMsg.MiddleMsgKey)
|
||||
continue
|
||||
}
|
||||
|
||||
// 发送事件到 全部的 plugs 里
|
||||
for _, val := range plugs {
|
||||
_, err := val.Exec(msg)
|
||||
if err != nil {
|
||||
logx.With(ctx, m.eventProduce).Errorln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package middle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
||||
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
|
||||
)
|
||||
|
||||
func Test_middleware_loadPlugins(t *testing.T) {
|
||||
m := NewMiddleWare()
|
||||
m.loadPlugins()
|
||||
|
||||
fmt.Println(m.plugins)
|
||||
}
|
||||
|
||||
func TestWorker(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
m := NewMiddleWare()
|
||||
|
||||
product := event.NewProduce(m.GetEventDriver())
|
||||
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.LogContext{
|
||||
Msg: "debug msg",
|
||||
})
|
||||
|
||||
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.PulginsInfos{
|
||||
Infos: []*middleMsg.PulginsInfo{
|
||||
{
|
||||
Desc: "miss",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.LruTTlContext{
|
||||
Keys: []string{"1", "2", "3"},
|
||||
})
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.17.3
|
||||
// source: base.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type BaseKey struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Ttl int64 `protobuf:"varint,2,opt,name=ttl,proto3" json:"ttl,omitempty"`
|
||||
Expire *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expire,proto3" json:"expire,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BaseKey) Reset() {
|
||||
*x = BaseKey{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_base_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *BaseKey) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BaseKey) ProtoMessage() {}
|
||||
|
||||
func (x *BaseKey) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_base_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BaseKey.ProtoReflect.Descriptor instead.
|
||||
func (*BaseKey) Descriptor() ([]byte, []int) {
|
||||
return file_base_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *BaseKey) GetKey() string {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BaseKey) GetTtl() int64 {
|
||||
if x != nil {
|
||||
return x.Ttl
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BaseKey) GetExpire() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.Expire
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type External struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *External) Reset() {
|
||||
*x = External{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_base_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *External) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*External) ProtoMessage() {}
|
||||
|
||||
func (x *External) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_base_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use External.ProtoReflect.Descriptor instead.
|
||||
func (*External) Descriptor() ([]byte, []int) {
|
||||
return file_base_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
var File_base_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_base_proto_rawDesc = []byte{
|
||||
0x0a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69,
|
||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x61, 0x0a,
|
||||
0x07, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74,
|
||||
0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x32, 0x0a, 0x06,
|
||||
0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65,
|
||||
0x22, 0x0a, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x42, 0x0b, 0x5a, 0x09,
|
||||
0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_base_proto_rawDescOnce sync.Once
|
||||
file_base_proto_rawDescData = file_base_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_base_proto_rawDescGZIP() []byte {
|
||||
file_base_proto_rawDescOnce.Do(func() {
|
||||
file_base_proto_rawDescData = protoimpl.X.CompressGZIP(file_base_proto_rawDescData)
|
||||
})
|
||||
return file_base_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_base_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_base_proto_goTypes = []interface{}{
|
||||
(*BaseKey)(nil), // 0: BaseKey
|
||||
(*External)(nil), // 1: External
|
||||
(*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp
|
||||
}
|
||||
var file_base_proto_depIdxs = []int32{
|
||||
2, // 0: BaseKey.expire:type_name -> google.protobuf.Timestamp
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_base_proto_init() }
|
||||
func file_base_proto_init() {
|
||||
if File_base_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_base_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*BaseKey); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_base_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*External); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_base_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_base_proto_goTypes,
|
||||
DependencyIndexes: file_base_proto_depIdxs,
|
||||
MessageInfos: file_base_proto_msgTypes,
|
||||
}.Build()
|
||||
File_base_proto = out.File
|
||||
file_base_proto_rawDesc = nil
|
||||
file_base_proto_goTypes = nil
|
||||
file_base_proto_depIdxs = nil
|
||||
}
|
|
@ -0,0 +1,733 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v3.17.3
|
||||
// source: channelx.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type CPushRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Value []string `protobuf:"bytes,2,rep,name=value,proto3" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CPushRequest) Reset() {
|
||||
*x = CPushRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CPushRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CPushRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CPushRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CPushRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CPushRequest) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *CPushRequest) GetKey() *BaseKey {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CPushRequest) GetValue() []string {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CPushResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
E *External `protobuf:"bytes,1,opt,name=e,proto3" json:"e,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CPushResponse) Reset() {
|
||||
*x = CPushResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CPushResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CPushResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CPushResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CPushResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CPushResponse) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *CPushResponse) GetE() *External {
|
||||
if x != nil {
|
||||
return x.E
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CPopRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Count int32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CPopRequest) Reset() {
|
||||
*x = CPopRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CPopRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CPopRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CPopRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CPopRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CPopRequest) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *CPopRequest) GetKey() *BaseKey {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CPopRequest) GetCount() int32 {
|
||||
if x != nil {
|
||||
return x.Count
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type CPopResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
E *External `protobuf:"bytes,1,opt,name=e,proto3" json:"e,omitempty"`
|
||||
Result []string `protobuf:"bytes,2,rep,name=result,proto3" json:"result,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CPopResponse) Reset() {
|
||||
*x = CPopResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CPopResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CPopResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CPopResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CPopResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CPopResponse) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *CPopResponse) GetE() *External {
|
||||
if x != nil {
|
||||
return x.E
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CPopResponse) GetResult() []string {
|
||||
if x != nil {
|
||||
return x.Result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CMakeRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Length int32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CMakeRequest) Reset() {
|
||||
*x = CMakeRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CMakeRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CMakeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CMakeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CMakeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CMakeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *CMakeRequest) GetKey() *BaseKey {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CMakeRequest) GetLength() int32 {
|
||||
if x != nil {
|
||||
return x.Length
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type CMakeResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *CMakeResponse) Reset() {
|
||||
*x = CMakeResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CMakeResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CMakeResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CMakeResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CMakeResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CMakeResponse) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
type CLenRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CLenRequest) Reset() {
|
||||
*x = CLenRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CLenRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CLenRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CLenRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[6]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CLenRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CLenRequest) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *CLenRequest) GetKey() *BaseKey {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CLenResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Length int32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CLenResponse) Reset() {
|
||||
*x = CLenResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CLenResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CLenResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CLenResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[7]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CLenResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CLenResponse) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *CLenResponse) GetLength() int32 {
|
||||
if x != nil {
|
||||
return x.Length
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type CCleanRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
}
|
||||
|
||||
func (x *CCleanRequest) Reset() {
|
||||
*x = CCleanRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CCleanRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CCleanRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CCleanRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[8]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CCleanRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CCleanRequest) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *CCleanRequest) GetKey() *BaseKey {
|
||||
if x != nil {
|
||||
return x.Key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CCleanResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *CCleanResponse) Reset() {
|
||||
*x = CCleanResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_channelx_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *CCleanResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CCleanResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CCleanResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_channelx_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CCleanResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CCleanResponse) Descriptor() ([]byte, []int) {
|
||||
return file_channelx_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
var File_channelx_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_channelx_proto_rawDesc = []byte{
|
||||
0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x1a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x0c,
|
||||
0x43, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03,
|
||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65,
|
||||
0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x28,
|
||||
0x0a, 0x0d, 0x43, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x17, 0x0a, 0x01, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x45, 0x78, 0x74,
|
||||
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52, 0x01, 0x65, 0x22, 0x3f, 0x0a, 0x0b, 0x43, 0x50, 0x6f, 0x70,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03,
|
||||
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3f, 0x0a, 0x0c, 0x43, 0x50, 0x6f,
|
||||
0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x01, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52,
|
||||
0x01, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x42, 0x0a, 0x0c, 0x43, 0x4d,
|
||||
0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65,
|
||||
0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x0f,
|
||||
0x0a, 0x0d, 0x43, 0x4d, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x29, 0x0a, 0x0b, 0x43, 0x4c, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
|
||||
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61,
|
||||
0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x26, 0x0a, 0x0c, 0x43, 0x4c,
|
||||
0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65,
|
||||
0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67,
|
||||
0x74, 0x68, 0x22, 0x2b, 0x0a, 0x0d, 0x43, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22,
|
||||
0x10, 0x0a, 0x0e, 0x43, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x42, 0x0b, 0x5a, 0x09, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_channelx_proto_rawDescOnce sync.Once
|
||||
file_channelx_proto_rawDescData = file_channelx_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_channelx_proto_rawDescGZIP() []byte {
|
||||
file_channelx_proto_rawDescOnce.Do(func() {
|
||||
file_channelx_proto_rawDescData = protoimpl.X.CompressGZIP(file_channelx_proto_rawDescData)
|
||||
})
|
||||
return file_channelx_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_channelx_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_channelx_proto_goTypes = []interface{}{
|
||||
(*CPushRequest)(nil), // 0: CPushRequest
|
||||
(*CPushResponse)(nil), // 1: CPushResponse
|
||||
(*CPopRequest)(nil), // 2: CPopRequest
|
||||
(*CPopResponse)(nil), // 3: CPopResponse
|
||||
(*CMakeRequest)(nil), // 4: CMakeRequest
|
||||
(*CMakeResponse)(nil), // 5: CMakeResponse
|
||||
(*CLenRequest)(nil), // 6: CLenRequest
|
||||
(*CLenResponse)(nil), // 7: CLenResponse
|
||||
(*CCleanRequest)(nil), // 8: CCleanRequest
|
||||
(*CCleanResponse)(nil), // 9: CCleanResponse
|
||||
(*BaseKey)(nil), // 10: BaseKey
|
||||
(*External)(nil), // 11: External
|
||||
}
|
||||
var file_channelx_proto_depIdxs = []int32{
|
||||
10, // 0: CPushRequest.key:type_name -> BaseKey
|
||||
11, // 1: CPushResponse.e:type_name -> External
|
||||
10, // 2: CPopRequest.key:type_name -> BaseKey
|
||||
11, // 3: CPopResponse.e:type_name -> External
|
||||
10, // 4: CMakeRequest.key:type_name -> BaseKey
|
||||
10, // 5: CLenRequest.key:type_name -> BaseKey
|
||||
10, // 6: CCleanRequest.key:type_name -> BaseKey
|
||||
7, // [7:7] is the sub-list for method output_type
|
||||
7, // [7:7] is the sub-list for method input_type
|
||||
7, // [7:7] is the sub-list for extension type_name
|
||||
7, // [7:7] is the sub-list for extension extendee
|
||||
0, // [0:7] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_channelx_proto_init() }
|
||||
func file_channelx_proto_init() {
|
||||
if File_channelx_proto != nil {
|
||||
return
|
||||
}
|
||||
file_base_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_channelx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CPushRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CPushResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CPopRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CPopResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CMakeRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CMakeResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CLenRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CLenResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CCleanRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_channelx_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*CCleanResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_channelx_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_channelx_proto_goTypes,
|
||||
DependencyIndexes: file_channelx_proto_depIdxs,
|
||||
MessageInfos: file_channelx_proto_msgTypes,
|
||||
}.Build()
|
||||
File_channelx_proto = out.File
|
||||
file_channelx_proto_rawDesc = nil
|
||||
file_channelx_proto_goTypes = nil
|
||||
file_channelx_proto_depIdxs = nil
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package proto
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type GetKeyBaseInterface interface {
|
||||
GetKey() *BaseKey
|
||||
}
|
||||
|
||||
const (
|
||||
BaseKeyMethodKey = "basekey"
|
||||
)
|
||||
|
||||
// NewBaseKey
|
||||
// key,ttl,expire
|
||||
func NewBaseKey(key string, t ...int64) *BaseKey {
|
||||
var expire *timestamppb.Timestamp = nil
|
||||
var ttl int64
|
||||
|
||||
if len(t) > 1 {
|
||||
expire = ×tamppb.Timestamp{
|
||||
Seconds: t[1],
|
||||
}
|
||||
ttl = t[0]
|
||||
} else if len(t) == 1 {
|
||||
ttl = t[0]
|
||||
}
|
||||
|
||||
return &BaseKey{
|
||||
Key: key,
|
||||
Expire: expire,
|
||||
Ttl: ttl,
|
||||
}
|
||||
}
|