package naming

import (
    "encoding/json"

    etcd "github.com/coreos/etcd/clientv3"
    "golang.org/x/net/context"

    "google.golang.org/grpc"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/naming"
)

// GRPCResolver creates a grpc.Watcher for a target to track its resolution changes.
//GRPCResolver  创建一个 grpc.Watcher对于目标对象,追踪目标对象的改变
type GRPCResolver struct {
    // Client is an initialized etcd client.
    Client *etcd.Client
}
//监听对象更新
func (gr *GRPCResolver) Update(ctx context.Context, target string, nm naming.Update, opts ...etcd.OpOption) (err error) {
    switch nm.Op {
    case naming.Add:
        var v []byte
        if v, err = json.Marshal(nm); err != nil {
            return grpc.Errorf(codes.InvalidArgument, err.Error())
        }
        _, err = gr.Client.KV.Put(ctx, target+"/"+nm.Addr, string(v), opts...)
    case naming.Delete:
        _, err = gr.Client.Delete(ctx, target+"/"+nm.Addr, opts...)
    default:
        return grpc.Errorf(codes.InvalidArgument, "naming: bad naming op")
    }
    return err
}

func (gr *GRPCResolver) Resolve(target string) (naming.Watcher, error) {
    ctx, cancel := context.WithCancel(context.Background())
    w := &gRPCWatcher{c: gr.Client, target: target + "/", ctx: ctx, cancel: cancel}
    return w, nil
}

type gRPCWatcher struct {
    c      *etcd.Client
    target string
    ctx    context.Context
    cancel context.CancelFunc
    wch    etcd.WatchChan
    err    error
}

// Next gets the next set of updates from the etcd resolver.
// Calls to Next should be serialized; concurrent calls are not safe since
// there is no way to reconcile the update ordering.
func (gw *gRPCWatcher) Next() ([]*naming.Update, error) {
    if gw.wch == nil {
        // first Next() returns all addresses
        return gw.firstNext()
    }
    if gw.err != nil {
        return nil, gw.err
    }

    // process new events on target/*
    wr, ok := <-gw.wch
    if !ok {
        gw.err = grpc.Errorf(codes.Unavailable, "naming: watch closed")
        return nil, gw.err
    }
    if gw.err = wr.Err(); gw.err != nil {
        return nil, gw.err
    }

    updates := make([]*naming.Update, 0, len(wr.Events))
    for _, e := range wr.Events {
        var jupdate naming.Update
        var err error
        switch e.Type {
        case etcd.EventTypePut:
            err = json.Unmarshal(e.Kv.Value, &jupdate)
            jupdate.Op = naming.Add
        case etcd.EventTypeDelete:
            err = json.Unmarshal(e.PrevKv.Value, &jupdate)
            jupdate.Op = naming.Delete
        }
        if err == nil {
            updates = append(updates, &jupdate)
        }
    }
    return updates, nil
}

func (gw *gRPCWatcher) firstNext() ([]*naming.Update, error) {
    // Use serialized request so resolution still works if the target etcd
    // server is partitioned away from the quorum.
    resp, err := gw.c.Get(gw.ctx, gw.target, etcd.WithPrefix(), etcd.WithSerializable())
    if gw.err = err; err != nil {
        return nil, err
    }

    updates := make([]*naming.Update, 0, len(resp.Kvs))
    for _, kv := range resp.Kvs {
        var jupdate naming.Update
        if err := json.Unmarshal(kv.Value, &jupdate); err != nil {
            continue
        }
        updates = append(updates, &jupdate)
    }

    opts := []etcd.OpOption{etcd.WithRev(resp.Header.Revision + 1), etcd.WithPrefix(), etcd.WithPrevKV()}
    gw.wch = gw.c.Watch(gw.ctx, gw.target, opts...)
    return updates, nil
}

func (gw *gRPCWatcher) Close() { gw.cancel() }

grpc.go的更多相关文章

  1. gRPC源码分析1-SSL/TLS

    引子 前几天看到微信后台团队分享了TLS相关文章,正好gRPC里TLS数据加密是很重要的一块,于是整理出了这篇文章. 在gRPC里,如果仅仅是用来做后端微服务,可以考虑不加密.本文太长,先给个大纲. ...

  2. gRPC源码分析2-Server的建立

    gRPC中,Server.Client共享的Class不是很多,所以我们可以单独的分别讲解Server和Client的源码. 通过第一篇,我们知道对于gRPC来说,建立Server是非常简单的,还记得 ...

  3. gRPC源码分析0-导读

    gRPC是Google开源的新一代RPC框架,官网是http://www.grpc.io.正式发布于2016年8月,技术栈非常的新,基于HTTP/2,netty4.1,proto3.虽然目前在工程化方 ...

  4. 谷歌发布的首款基于HTTP/2和protobuf的RPC框架:GRPC

    Google 刚刚开源了grpc,  一个基于HTTP2 和 Protobuf 的高性能.开源.通用的RPC框架.Protobuf 本身虽然提供了RPC  的定义语法,但是一直以来,Google 只开 ...

  5. gRPC .NET Core跨平台学习

    前些天发布gRPC C# 学习,在.NET Framework 中使用gRPC ,今天来学习 .NET Core gRPC. gRPC 的.NET Core 包在NuGet 上发布了,结合.NET C ...

  6. gRPC C#学习

    前些天gRPC 发布1.0 版本,代表着gRPC 已经正式进入稳定阶段. 今天我们就来学习gRPC C# .而且目前也已经支持.NET Core 可以实现完美跨平台. 传统的.NET 可以通过Mono ...

  7. .net core 用grpc实现微服务

    GRPC 是Google发布的一个开源.高性能.通用RPC(Remote Procedure Call)框架.提供跨语言.跨平台支持.以下以.NET Core 使用控制台.docker中演示如何使用G ...

  8. rpc框架之gRPC 学习 - hello world

    grpc是google在github于2015年开源的一款RPC框架,虽然protobuf很早google就开源了,但是google一直没推出正式的开源框架,导致github上基于protobuf的r ...

  9. Android开发笔记之《远程控制(MQTT|mosquitto) && (ProtocalBuffer | GRPC)》

    Android推送方案分析(MQTT/XMPP/GCM): http://www.open-open.com/lib/view/open1410848945601.htmlMQTT官网: http:/ ...

  10. gRPC+etcd的优势分析

    相比webService等可跨平台,跨语言的服务相比,gRPC更增加了以下优势 1.可以采用二进制传输,速度更快 (使用TCP传输层,而不是Http2应用层) 2.集群服务,统一注册,可靠性高( 好的 ...

随机推荐

  1. JS基础速成(三)- DOM(文件对象模型)

    .t1 { background-color: #ff8080; width: 1100px; height: 40px } 一.DOM树的基本结构 DOM节点分为三大类:元素节点(标签节点),属性节 ...

  2. WSGI及gunicorn指北(二)

    pyg0已经大概了解了wsgi.现在他决定深入探索他们实际在生产环境里用到的web 服务器 -gunicorn. 先来看看官网的介绍:Gunicorn 是一个运行在Unix上的python WSGI ...

  3. RabbitMQ学习总结

    关于RabbitMQ是什么以及它的概念,不了解的可以先查看一下下面推荐的几篇博客 https://blog.csdn.net/whoamiyang/article/details/54954780 h ...

  4. 面试(三)---volatile

    一.前言       最近去成都玩了一圈,整体感觉还不错,辞职以后工作找的也很顺利,随着年龄增加自己也考虑定居和个人长期发展的问题,反正乱七八糟的事,总之需要好好屡屡思路,不能那么着急下定论,当然我对 ...

  5. Rafy 开源贡献中心 - 组织成立,并试运行一月小结

    背景 最近两年,工作中虽然大量使用了 Rafy 框架作为各个产品.项目的开发框架.我是 2015 年的年中加入现在这家公司的,由于我个人工作太忙的缘故,一直没怎么编码,Rafy 框架底层的核心成长也比 ...

  6. Leetcode_删除排序数组中的重复项

    Leetcode  删除排序数组中的重复项 题目: 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用 额外的数组空间,你必须在原地修改输入数 ...

  7. 高性能网络IO模型

    同步阻塞式IO开发简单,但在处理IO密集的并发任务时,非常浪费CPU资源,性能低:并且,当一个进程(线程)含有多个套接字上时,同步阻塞式IO会带来问题:因为同步阻塞式IO只支持进程(线程)阻塞在一个套 ...

  8. 115个Java面试题和答案——终极列表(上)【转】

    本文我们将要讨论Java面试中的各种不同类型的面试题,它们可以让雇主测试应聘者的Java和通用的面向对象编程的能力.下面的章节分为上下两篇,第一篇将要讨论面向对象编程和它的特点,关于Java和它的功能 ...

  9. python new和init知识点

    __new__ 方法是什么?如果将类比喻为工厂,那么__init__()方法则是该工厂的生产工人,__init__()方法接受的初始化参 数则是生产所需原料,__init__()方法会按照方法中的语句 ...

  10. jsp 条件查询、列表分页

    条件查询 dao //根据搜索条件筛选数据 public List<User> GetUserBySearch(String userName, String sex) throws SQ ...