Nitro's

Feb 19, 2020 - Comments - translate tech golang

Golang依赖包管理知多少(4)-v2与后续版本

前言 成功的项目随着逐步成熟以及新功能的加入,过去的特性和设计方案可能不能满足需求。开发者可能想整合一下他们所学的知识比如移除废弃函数、重命名参数或者分割复杂的包为多个可维护模块。这些变更都需要下游用户付出努力来迁移他们的代码来适配新的API,所以他们不会没有认真权衡过收益和成本而做出变更的。 对于一些还在实验中的项目,比如主版本为v0的项目,用户会预期到偶尔的重大变更。对于已经发布为稳定版本的项目,比如主版本为v1或者更高版本的项目,重大的变更需要在一个大版本上进行。这篇文章主要介绍了大版本策略、如果创建并发布一个新的大版本以及如何维护一个module的多个主版本。 主版本与module path 主版本策略 发布v2及后续版本 主版本与module path modules模式规范了一个重要的原则,导入兼容性原则: 如果一个老版本的包和一个新版本的包使用相同的导入path,那么新版本的包必须向后兼容老版本的包。 一个新的大版本的包不会向后兼容之前的版本。这就意味着一个新的大版本module必须有一个不同于历史版本的module path。从v2版本开始,大版本号必须紧跟在module path后面(声明在go.mod文件的module语句后面)。比如,当一名开发者开发了github.com/googleapis/gax-go module的v2时,他需要使用新的module path-github.com/googleapis/gax-go/v2,如果用户想使用这个module的v2版本就必须要改变他们的包导入以及module依赖到github.com/googleapis/gax-go/v2。 大版本后缀在module path上是module模式不同于其他依赖管理工具的地方。后缀方式可以解决菱形依赖问题。在module模式之前,gopkg.in允许软件维护者遵循我们现在的这套导入兼容性规则,如果你的module依赖一个包gopkg.in/yaml.v1,另外的一个module依赖gopkg.in/yaml.v2,这时是不会有冲突的,因为这两个yaml 包使用了不同的module path,和module模式类似 gopkg.in也适用了后缀方式。由于gopkg.in使用了module模式相同的后缀版本技术,所以go命令兼容gopkg.in中.v2作为版本后缀,但这仅针对gopkg.in,托管在其他域名下的module还是需要使用/v2这种后缀方式。 主版本策略 在开发v2以及后续版本时推荐的方式是创建一个对应版本号的文件目录。 github.com/googleapis/gax-go @ master branch /go.mod → module github.com/googleapis/gax-go /v2/go.mod → module github.com/googleapis/gax-go/v2 这样做并不是为了module模式,主要为了兼容一些工具:在仓库中的文件路径正好是GOPATH模式中go get中所需要的路径。这种方式也方便把所有的大版本按照不同的目录来进行开发。 其他的策略也有按照不同的大版本放在不同的分支,但是如果v2+版本的源代码放在仓库的默认分支(通常是master),像GOPATH下的go这类的工具又不识别版本可能就不能区分不同的大版本。 由于不同的大版本放在不同的子目录这一策略的兼容性好,本文的例子将会遵循这个策略。如果他们让用户维持GOPATH模式,那我们建议module的开发者遵循这一策略。 发布v2及后续版本 本文使用github.com/googleapis/gax-go作为例子: $ pwd /tmp/gax-go $ ls CODE_OF_CONDUCT.md call_option.go internal CONTRIBUTING.md gax.go invoke.go LICENSE go.mod tools.go README.md go.sum RELEASING.md header.go $ cat go.mod module github.com/googleapis/gax-go go 1.

Feb 18, 2020 - Comments - translate tech golang

Golang依赖包管理知多少(3)-发布一个module

前言 这篇文章将讨论如何编写并发布可被其他module依赖引用的一个module。 注意:这篇主要涉及开发配置直至v1版本,如果你对v2版本迭代感兴趣,可以参考v2版本与版本迭代。 本文默认使用Git作为例子, 但是Mercurial、Bazaar等其他版本管理工具也是支持的。 项目配置 版本与module v0-初始版本、非稳定版本 v1-第一个稳定版本 项目配置 本文需要你有一个已经存在的项目作为例子,所以我们以认识Go modules文章结尾的文件为例子: $ cat go.mod module example.com/hello go 1.12 require rsc.io/quote/v3 v3.1.0 $ cat go.sum golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= $ cat hello.go package hello import "rsc.io/quote/v3" func Hello() string { return quote.HelloV3() } func Proverb() string { return quote.Concurrency() } $ cat hello_test.go package hello import ( "testing" ) func TestHello(t *testing.

Feb 16, 2020 - Comments - translate tech golang

Golang依赖包管理知多少

前言 本文内容结合自己的理解,对Golang官方博客针对Golang新版本modules包管理系统的文章翻译。 使用Go modules Go从1.11和1.12已经初步支持modules,新版Go包依赖管理系统通过显性的版本依赖使得更加易于维护。这篇文章主要介绍了在开始使用Golang modules时的一些基本操作。 一个module是许多Go Pakcage的集合,在它的根目录有一个go.mod文件。go.mod文件中定义这个module的module路径,也定义了需要导入的module路径、外部依赖,这些都是modules成功构建所必须的。每一个外部依赖都有一个module路径和版本号组成。 从Go 1.11开始,如果当前目录或者它的父级目录中有go.mod文件并且此目录不在$GOPATH/src下面,go命令就会开启对modules的支持(如果在$GOPATH/src目录下,为了保持兼容即便存在go.mod文件go命令还会使用原有的GOPATH模式)。从Go 1.13开始module模式就会默认启用了。 下面就开始介绍在使用module模式开发Go代码过程中的几个步骤: 创建一个新的module 增加一个依赖包 升级依赖包的小版本 增加一个大版本的依赖包 升级一个依赖包到大版本 移除未使用的依赖包 创建一个新的module 创建一个不在\$GOPATH/src的空目录,cd到这个目录,然后创建一个golang源文件hello.go: package hello func Hello() string { return "Hello,World." } 再写一个测试用例: package hello import "testing" func TestHello(t *testing.T) { want: "Hello,World." if got := Hello(); got != want { t.Errorf("Hello() = %q, want %q", got, want) } } 到这里时,目录下已经包含一个package了,但是它还不是一个module因为它缺少 go.mod 文件。下面在这个目录下运行 go test 执行单元测试,我们会看到: $ go test PASS ok _/home/gopher/hello 0.

Feb 16, 2020 - Comments - translate tech golang

Golang依赖包管理知多少(2)-迁移工程到modules模式

前言 在golang工程中可以使用多种依赖管理策略,像dep、glide这种Vendoring工具非常的流行,但是它们又各自为政并不能很好的兼容。很多项目把工程文件放在GOPATH目录下存储为一个Git仓库,其他人通过go get命令依赖存放在GOPATH中最新版本的代码。 Go modules系统在Go1.11时发布,它通过go命令提供了一个官方的依赖管理解决方案。这篇文章主要讲述了迁移原有工程到modules的一些工具和技术。 注意:如果你的工程已经标记为v2.0.0或者更高版本,在增加go.mod文件时需要更新工程中的module path。我们将会在后面的文章中解释如何做才能在v2或者更高版本时不让你的用户糟心。 原工程中使用了依赖管理工具 使用一个依赖管理器 不使用依赖管理器 在modules模式下的测试用例 发布一个版本 导入和规范module path 原工程中使用了依赖管理工具 为了转换一个使用依赖管理工具的工程,需要执行以下命令: $ git clone https://github.com/my/project [...] $ cd project $ cat Godeps/Godeps.json { "ImportPath": "github.com/my/project", "GoVersion": "go1.12", "GodepVersion": "v80", "Deps": [ { "ImportPath": "rsc.io/binaryregexp", "Comment": "v0.2.0-1-g545cabd", "Rev": "545cabda89ca36b48b8e681a30d9d769a30b3074" }, { "ImportPath": "rsc.io/binaryregexp/syntax", "Comment": "v0.2.0-1-g545cabd", "Rev": "545cabda89ca36b48b8e681a30d9d769a30b3074" } ] } $ go mod init github.com/my/project go: creating new go.mod: module github.com/my/project go: copying requirements from Godeps/Godeps.

Aug 17, 2019 - Comments - dev tech golang

Goim单机配置启动简单记录

Goim v2.0.0为例 运行环境:MacOS 10.14 依赖组件、框架 Java Kafka依赖 Kafka 消息队列 Zookeeper Kafka依赖 Redis 在线状态、服务状态缓存 Discovery 服务注册、发现框架 配置 Redis配置 host=localhost port=6379 ZooKeeper配置 host=localhost port=2081 Kafka配置 host=localhost port=9092 job job -conf=goim/cmd/job/job-example.toml -region=sh -zone=sh001 -deploy.env=dev comet comet -conf=goim/cmd/comet/comet-example.toml -region=sh -zone=sh001 -deploy.env=dev -weight=10 -addrs=127.0.0.1 logic logic -conf=goim/cmd/logic/logic-example.toml -region=sh -zone=sh001 -deploy.env=dev -weight=10 启动 Zookeeper 支持Kafka的运行 Kafka 消息队列启动,业务Push消息到这里 Redis 用户在线状态、服务状态的缓存服务启动 Discovery 启动服务注册、发现框架 logic启动,接收业务Push消息,推送到消息队列 comet启动,接受用户注册、连接注册、消息下发 job启动,读取消息队列,发送到comet 测试 通过源代码中的example,测试连通性是否正确,通过RPC的Push接口发送消息测试。

May 19, 2019 - Comments - tech

Retrofit、Volley、HttpClient比较

Retrofit作为现在大家用的最多HTTP请求框架,非常流行,Github上star 3w+。它为什么能超越Volley、HTTPClient能够一枝独秀呢?那先看看其他两个HTTP栈的实现。 HTTPClient Java界老牌HTTP栈实现,由Apache维护,它支持HTTP1.0/1.1、极其丰富的API来支持各种子协议,代码庞大臃肿也变成了它的缺点,虽然它的创建一开始是为了弥补Java SDK中java.net包HTTP请求的简单实现,Android在6.0以后彻底弃用了它,转而推荐使用HTTPURLConnection。 Volley 作为Google官方开源的一款HTTP栈,它支持切换HTTPURLConnection、HTTPClient底层协议栈的切换,同时提供了请求线程池、缓存的支持,刚一推出也是收获许多赞赏,但是它就像G家好多产品一样,几年一次的维护和有些bug都需要使用方去维护解决,都是开发者逐渐抛弃的原因。虽然从Volley开始,这些HTTP栈的实现都在逐渐向上层实现,因为不管是Android、iOS大部分App的网络交互都是Restful-API的实现,所以能在提供基础HTTP服务的基础上,提供请求内容的封装、响应内容的解析就越来越迫切,Volley在这方便做出了第一步,响应内容的解析以及支持自定义解析这些功能。但是Volley的致命问题在于它的响应内容处理上,必须将全部数据读取出来交给上层数据,这对内存的要求可能很高,缺乏一定的灵活性,所以只适合小数据量的HTTP请求。 Retrofit 来自Android界开源大厂Square.Inc ,底层HTTP栈来自于OKHTTP框架,它支持HTTP 1.1/2,支持TLS,HTTP2作为socket连接复用的最新技术,OKHTTP的支持可以说是一大重点,因为作为移动端App,相比浏览器中的Web开发,App端点的可控性可以让我们快速支持这种技术来提高加载速度,同时OKHTTP提供了请求拦截器方便我们在请求发起前的对参数进行操纵。 Retrofit建立在OKHTTP的基石之上,抽象出了Converter、CallAdapter这两个重要的概念。 Coverter作为HTTP请求、响应内容的类型服务类为上层不同的技术实现提供支持,现在支持GSON、Guava、JSON、XML、Protobuf,同样你可以根据自己的需求进行定制。 CallAdapter则为不同的上层框架提供了容器支持,让你能够在Retrofit的基础上同步、异步的分发请求与响应,现在支持Java8、RxJava、RxJava2的标准实现。 除此之外,动态代理、注解编程的使用,让开发者从复杂的请求参数、URL拼接中解放出来,更多的去关心业务逻辑的实现。 这一系列的优势让Retrofit逐渐得到开发者的青睐。 番外: 在Java11 OpenJDK的文档中看到另外一个HTTPClient的实现,支持HTTP2、支持上层RxJava编程,但这对于Android平台来说JDK 11还是有点远。 参考资料: OKHTTP JDK Httpclient

May 18, 2019 - Comments - tech

Java动态代理类的生成和调用

Java的动态代理在开发中都有大量的使用,如Spring框架,Android的HTTP开发框架Retrofit,本文主要关注动态代理编写使用背后的代理类是如何的生成以及与代理对象的调用是如何实现的,以Retrofit这个框架中动态代理的使用为例子进行分析。 在Retrofit中,某类的API接口大多定义在一个Service接口类中,某一个API接口则被声明为Service接口类的一个方法,通过方法的注解、参数来描述具体API参数等信息。在调用某个API接口时,Retrofit实例调用create()创建Service接口类的实例对象来完成调用,具体源代码如下: public <T> T create(final Class<T> service) { // 必须是接口,并且不允许是继承来的接口 Utils.validateServiceInterface(service); //是否预加载 if (validateEagerly) { eagerlyValidateMethods(service); } //动态代理的核心代码 return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { private final Platform platform = Platform.get(); @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { // If the method is a method from Object then defer to normal invocation. if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args); } if (platform.

May 6, 2019 - Comments - dev tech

SVG Path命令属性

Android从5.0开始支持SVG矢量图,通过Vector Asset工具将SVG文件转换VectorDrawable定义的XML文件中,在运行时inflate这个xml文件来绘制图层,这对于减小APK资源文件体积和避免混乱的分辨率支持上都有很好的效果,同时Android通过Support支持库的形式给予了低版本的支持。 Android上对SVG的支持是受限制的,仅支持SVG tiny1.2版本的属性和标签,而且不支持text标签。 path标签是SVG中最常用的标签,这其中最重要的属性就是d(command)属性,它标明这个路径的绘制起点、终点、中间路径关键点、两点之间是否为直线、弧线、贝塞尔曲线等等。 d(command)属性主要分几类: 起点 用M、m来表示,如M150,0 表示从path的起点, 从x-150,y=0的坐标起点开始绘制 终点 用Z、z来表示,无参数 表示path的终点,链接到path的起点,闭合path,然后结束绘制 直线 假设当前点坐标为(10,10) L、l表示直线线段,如L100,100,表示从(10,10)开始,绘制一条到(100,100)的直线线段 H、h表示水平线段,如H100,表示从(10,10)开始,绘制一条到(100,10)的水平线段,等同于L100,10 V、v表示垂直线段,如V150,表示从(10,10)开始,绘制一条到(10,150)的垂直线段,等同于L10,150 三次贝塞尔曲线 假设当前点坐标为(100,200) C、c表示三次贝塞尔曲线,如C100,100 250,100 250,200,表示起点坐标为(100,200),控制点1坐标为(100,100),控制点2坐标为(250,100),终点坐标为(250,200),绘制这一条三次贝塞尔曲线线段。 S、s也表示贝塞尔曲线,只是它比较特殊,它的控制点1来自于上一条C、c、S、s曲线的控制点2坐标与上一条C、c、S、s曲线终点坐标连线上的对称点, 就如上面的例子,S曲线的控制点1坐标就为(250,300),这样的曲线在连贯性上是平滑曲线,所以也称为是平滑三次贝塞尔曲线; 如果上一条线段不是C、c、S、s三次贝塞尔曲线,那么默认它的控制点1坐标与起点坐标一致; 如S400,300 400,200,假设沿着上一条S贝塞尔曲线继续绘制,则起点坐标为(250,200),控制点1坐标为(250,300),控制点2坐标为(400,300),终点坐标为(400,200)。 二次贝塞尔曲线 假设当前点坐标为(200,300) Q、q表示二次贝塞尔曲线,如Q400,50 600,300,表示起点坐标为(200,300),控制点坐标为(400,50),终点坐标为(600,300),然后绘制一条二次贝塞尔曲线线段。 T、t也表示二次贝塞尔曲线,如同S、s平滑三次贝塞尔曲线一样,它“借用”了上一次二次贝塞尔曲线的控制点,取上次曲线控制点与上次曲线的终点坐标连线上对称点为新的控制点; 如果上一条线段不是Q、q、T、t二次贝塞尔曲线线段,那么默认它的控制点坐标与起点坐标一致。 如T1000,300,假设沿着上一条Q二次贝塞尔曲线继续绘制,则起点坐标为(600,300),控制点为(800,550),终点坐标为(1000,300)。 椭圆曲线 假设当前点坐标为(50,-25) A、a表示椭圆曲线,如a25,25 -30 0,1 50,-25 l 50,-25,表示椭圆半径rx=25,ry=25,x轴方向上的旋转角度-30。 参考资料: SVGwg.org Path Mozilla SVG

Mar 24, 2019 - Comments - tech

Blink内核相关术语、映射关系

在读Adblock Plus for Chrome插件的源代码时,拦截入口处有几个判断非常重要,这涉及到当前打开Tab的URL、来源、打开方式等概念,对应到Blink中术语有page、main frame、iframe、document等,翻阅一下Blink的README文档,找到官方的介绍在此做一下记录。 Page 一个Page对应于一个Tab,当然前提时OOPIF(Out-of-Process iframes)没有开启。每一个渲染进程可能包含多个Tab。 Frame Frame对应于HTML中的frame,可能是主frame或者iframe,每个Page在树形结构中可能包含一个或者多个frame。 DOMWindow 一个DOMWindow对应Javascript中的一个window对象,每个Frame有一个DOMWindow。 Document 一个Document对应Javascript中的一个window.document,每个Frame有一个Document。 ExecutionContext 一个ExecutionContext是一个抽象概念,在渲染进程的主线程中对应于一个Document,在工作者线程中对应于一个WorkerGlobalScope。 解释完这些,那就知道相互之间的对应关系了。 渲染进程:Page=1:N Page:Frame=1:M Frame:DOMWindow:Document(ExecutionContext)=1:1:1 这在某个时刻是成立的,因为某个时间段内涉及到iframe的locatio跳转新建frame以及frame的重用问题。