Skip to content

Commit

Permalink
release etcd
Browse files Browse the repository at this point in the history
  • Loading branch information
askuy committed Apr 20, 2022
0 parents commit 2f0ff8c
Show file tree
Hide file tree
Showing 34 changed files with 3,442 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://cdn.gocn.vip/gotomicro/s.jpeg
38 changes: 38 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]

**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]

**Additional context**
Add any other context about the problem here.
10 changes: 10 additions & 0 deletions .github/ISSUE_TEMPLATE/custom.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''

---


20 changes: 20 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.
20 changes: 20 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Go

on:
push:
pull_request:

jobs:

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.16

- name: Build
run: go build -v ./...
45 changes: 45 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Git命令简介
准备工作: 如果你没有github账号, 您需要申请一个Github账号, 接下来可以继续下一步.

## 1 Fork 代码
1. 访问 https://github.com/ego-component/eetcd
2. 点击 "Fork" 按钮 (位于页面的右上方)

## 2 Clone 代码
一般我们推荐将origin设置为官方的仓库,而设置一个自己的upstream。

如果已经在github上开启了SSH,那么我们推荐使用SSH,否则使用HTTPS。两者之间的区别在于,使用HTTPS每次推代码到远程库的时候,都需要输入身份验证信息。
而我们强烈建议,官方库永远使用HTTPS,这样可以避免一些误操作。

```bash
git clone https://github.com/ego-component/eetcd.git
cd eetcd
git remote add upstream 'git@github.com:<your github username>/eetcd.git'
```
upstream可以替换为任何你喜欢的名字。比如说你的用户名,你的昵称,或者直接使用me。后面的命令也要执行相应的替换。

## 3 同步代码
除非刚刚把代码拉到本地,否则我们需要先同步一下远程仓库的代码。
git fetch

在不指定远程库的时候,这个指令只会同步origin的代码。如果我们需要同步自己fork出来的,可以加上远程库名字:
git fetch upstream

## 4 创建 feature 分支
我们在创建新的 feature 分支的时候,要先考虑清楚,从哪个分支切出来。
我们假设,现在我们希望添加的特性将会被合并到master分支,或者说我们的新特性要在master的基础上进行,执行:
```bash
git checkout -b feature/my-feature origin/master
```
这样我们就切出来一个分支了。该分支的代码和origin/master上的完全一致。

## 5 提交 commit
```bash
git add .
git commit
git push upstream my-feature
```

## 6 提交 PR
访问 https://github.com/ego-component/eetcd,
点击 "Compare" 比较变更并点击 "Pull request" 提交 PR
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 gotomicro

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
217 changes: 217 additions & 0 deletions component.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package eetcd

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"strings"
"time"

"github.com/gotomicro/ego/core/elog"
grpcprom "github.com/grpc-ecosystem/go-grpc-prometheus"
"go.etcd.io/etcd/api/v3/mvccpb"
"go.etcd.io/etcd/client/v3"
"go.etcd.io/etcd/client/v3/concurrency"
"google.golang.org/grpc"
)

const PackageName = "component.eetcd"

// Component ...
type Component struct {
name string
config *config
logger *elog.Component
*clientv3.Client
}

// New ...
func newComponent(name string, config *config, logger *elog.Component) *Component {
dialOptions := []grpc.DialOption{
grpc.WithUnaryInterceptor(grpcprom.UnaryClientInterceptor),
grpc.WithStreamInterceptor(grpcprom.StreamClientInterceptor),
grpc.FailOnNonTempDialError(config.EnableFailOnNonTempDialError),
}

if config.EnableBlock {
dialOptions = append(dialOptions, grpc.WithBlock())
}

conf := clientv3.Config{
Endpoints: config.Addrs,
DialTimeout: config.ConnectTimeout,
DialKeepAliveTime: 10 * time.Second,
DialKeepAliveTimeout: 3 * time.Second,
DialOptions: dialOptions,
AutoSyncInterval: config.AutoSyncInterval,
}

if config.Addrs == nil {
logger.Panic("client etcd endpoints empty", elog.FieldValueAny(config))
}

logger = logger.With(elog.FieldAddr(fmt.Sprintf("%s", config.Addrs)))

if !config.EnableSecure {
conf.DialOptions = append(conf.DialOptions, grpc.WithInsecure())
}

if config.EnableBasicAuth {
conf.Username = config.UserName
conf.Password = config.Password
}

tlsEnabled := false
tlsConfig := &tls.Config{
InsecureSkipVerify: false,
}

if config.CaCert != "" {
certBytes, err := ioutil.ReadFile(config.CaCert)
if err != nil {
logger.Panic("parse CaCert failed", elog.Any("err", err))
}

caCertPool := x509.NewCertPool()
ok := caCertPool.AppendCertsFromPEM(certBytes)

if ok {
tlsConfig.RootCAs = caCertPool
}
tlsEnabled = true
}

if config.CertFile != "" && config.KeyFile != "" {
tlsCert, err := tls.LoadX509KeyPair(config.CertFile, config.KeyFile)
if err != nil {
logger.Panic("load CertFile or KeyFile failed", elog.Any("config", config), elog.Any("err", err))
}
tlsConfig.Certificates = []tls.Certificate{tlsCert}
tlsEnabled = true
}

if tlsEnabled {
conf.TLS = tlsConfig
}

client, err := clientv3.New(conf)
if err != nil {
logger.Panic("client etcd start panic", elog.FieldErr(err), elog.FieldValueAny(config))
}

cc := &Component{
name: name,
logger: logger,
Client: client,
config: config,
}

logger.Info("dial etcd server")
return cc
}

// GetKeyValue queries etcd key, returns mvccpb.KeyValue
func (c *Component) GetKeyValue(ctx context.Context, key string) (kv *mvccpb.KeyValue, err error) {
rp, err := c.Client.Get(ctx, key)
if err != nil {
return nil, err
}

if len(rp.Kvs) > 0 {
return rp.Kvs[0], nil
}

return
}

// GetPrefix get prefix
func (c *Component) GetPrefix(ctx context.Context, prefix string) (map[string]string, error) {
var (
vars = make(map[string]string)
)

resp, err := c.Get(ctx, prefix, clientv3.WithPrefix())
if err != nil {
return vars, err
}

for _, kv := range resp.Kvs {
vars[string(kv.Key)] = string(kv.Value)
}

return vars, nil
}

// DelPrefix 按前缀删除
func (c *Component) DelPrefix(ctx context.Context, prefix string) (deleted int64, err error) {
resp, err := c.Delete(ctx, prefix, clientv3.WithPrefix())
if err != nil {
return 0, err
}
return resp.Deleted, err
}

// GetValues queries etcd for keys prefixed by prefix.
func (c *Component) GetValues(ctx context.Context, keys ...string) (map[string]string, error) {
var (
firstRevision = int64(0)
vars = make(map[string]string)
maxTxnOps = 128
getOps = make([]string, 0, maxTxnOps)
)

doTxn := func(ops []string) error {
txnOps := make([]clientv3.Op, 0, maxTxnOps)

for _, k := range ops {
txnOps = append(txnOps, clientv3.OpGet(k,
clientv3.WithPrefix(),
clientv3.WithSort(clientv3.SortByKey, clientv3.SortDescend),
clientv3.WithRev(firstRevision)))
}

result, err := c.Txn(ctx).Then(txnOps...).Commit()
if err != nil {
return err
}
for i, r := range result.Responses {
originKey := ops[i]
originKeyFixed := originKey
if !strings.HasSuffix(originKeyFixed, "/") {
originKeyFixed = originKey + "/"
}
for _, ev := range r.GetResponseRange().Kvs {
k := string(ev.Key)
if k == originKey || strings.HasPrefix(k, originKeyFixed) {
vars[string(ev.Key)] = string(ev.Value)
}
}
}
if firstRevision == 0 {
firstRevision = result.Header.GetRevision()
}
return nil
}
for _, key := range keys {
getOps = append(getOps, key)
if len(getOps) >= maxTxnOps {
if err := doTxn(getOps); err != nil {
return vars, err
}
getOps = getOps[:0]
}
}
if len(getOps) > 0 {
if err := doTxn(getOps); err != nil {
return vars, err
}
}
return vars, nil
}

// GetLeaseSession 创建租约会话
func (c *Component) GetLeaseSession(ctx context.Context, opts ...concurrency.SessionOption) (leaseSession *concurrency.Session, err error) {
return concurrency.NewSession(c.Client, opts...)
}
Loading

0 comments on commit 2f0ff8c

Please sign in to comment.