Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 12 additions & 32 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ on:
branches: [main]
tags: ["*"]
pull_request:
env:
GO111MODULE: on
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
Expand All @@ -22,39 +20,24 @@ jobs:
arch:
- x64
- x86
# include:
# # test macOS and Windows with latest Julia only
# - os: macOS-latest
# arch: x64
# version: 1
# - os: windows-latest
# arch: x64
# version: 1
# - os: windows-latest
# arch: x86
# version: 1
include:
# test macOS and Windows with latest Julia only
- os: macOS-latest
arch: x64
version: 1
- os: windows-latest
arch: x64
version: 1
- os: windows-latest
arch: x86
version: 1
steps:
- uses: actions/checkout@v2
- name: setup go
uses: actions/setup-go@v2
with:
go-version: '1.12.9'
- run: go version
- name: setup protoc
uses: arduino/setup-protoc@v1
with:
version: '3.x'
- run: protoc --version
- name: generate test certificates
run: test/certgen/certgen.sh
shell: bash
- name: install protoc-gen-go
run: |
go get google.golang.org/protobuf/cmd/protoc-gen-go google.golang.org/grpc/cmd/protoc-gen-go-grpc
shell: bash
- name: start test server
run: test/runserver.sh
shell: bash
- uses: julia-actions/setup-julia@v1
with:
version: ${{ matrix.version }}
Expand All @@ -74,7 +57,4 @@ jobs:
- uses: julia-actions/julia-processcoverage@v1
- uses: codecov/codecov-action@v1
with:
file: lcov.info
- name: shutdown test server
run: kill `cat test/grpc-go/examples/route_guide/server.pid`
shell: bash
file: lcov.info
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ julia = "1.3"

[extras]
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Sockets = "6462fe0b-24de-5631-8697-dd941f90decc"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test", "Random"]
test = ["Random", "Sockets", "Test"]
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

A Julia gRPC Client.

GitHub Actions : [![Build Status](https://github.com/JuliaComputing/gRPCClient.jl/workflows/CI/badge.svg)](https://github.com/JuliaComputing/gRPCClient.jl/actions?query=workflow%3ACI+branch%3Amain)

[![Coverage Status](https://coveralls.io/repos/JuliaComputing/gRPCClient.jl/badge.svg?branch=main)](https://coveralls.io/r/JuliaComputing/gRPCClient.jl?branch=main)
[![Build Status](https://github.com/JuliaComputing/gRPCClient.jl/workflows/CI/badge.svg)](https://github.com/JuliaComputing/gRPCClient.jl/actions?query=workflow%3ACI+branch%3Amain)
[![codecov.io](http://codecov.io/github/JuliaComputing/gRPCClient.jl/coverage.svg?branch=main)](http://codecov.io/github/JuliaComputing/gRPCClient.jl?branch=main)


Expand Down Expand Up @@ -72,6 +70,8 @@ arguments passed to its constructor.
gRPCController(;
[ maxage::Int = 0, ]
[ keepalive::Int64 = 60, ]
[ negotiation::Symbol = :http2_prior_knowledge, ]
[ revocation::Bool = true, ]
[ request_timeout::Real = Inf, ]
[ connect_timeout::Real = 0, ]
[ verbose::Bool = false, ]
Expand All @@ -82,6 +82,10 @@ gRPCController(;
be reused (default 180 seconds, same as setting this to 0).
- `keepalive`: interval (seconds) in which to send TCP keepalive messages on
the connection (default 60 seconds).
- `negotiation`: how to negotiate HTTP2, can be one of `:http2_prior_knowledge`
(no negotiation, the default), `:http2_tls` (http2 upgrade but only over
tls), or `:http2` (http2 upgrade)
- `revocation`: whether to check for certificate recovation (default is true)
- `request_timeout`: request timeout (seconds)
- `connect_timeout`: connect timeout (seconds) (default is 300 seconds, same
as setting this to 0)
Expand Down
18 changes: 14 additions & 4 deletions src/curl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ end

function send_data(easy::Curl.Easy, input::Channel{T}) where T <: ProtoType
while true
yield()
data = isready(input) ? to_delimited_message_bytes(take!(input)) : isopen(input) ? UInt8[] : nothing
easy.input === nothing && break
easy.input = data
Expand All @@ -38,12 +39,19 @@ function grpc_headers()
headers
end

function easy_handle(maxage::Clong, keepalive::Clong)
function easy_handle(maxage::Clong, keepalive::Clong, negotiation::Symbol, revocation::Bool)
easy = Curl.Easy()
Curl.setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0)
http_version = (negotiation === :http2) ? CURL_HTTP_VERSION_2_0 :
(negotiation === :http2_tls) ? CURL_HTTP_VERSION_2TLS :
(negotiation === :http2_prior_knowledge) ? CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE :
throw(ArgumentError("unsupported HTTP2 negotiation mode $negotiation"))
Curl.setopt(easy, CURLOPT_HTTP_VERSION, http_version)
Curl.setopt(easy, CURLOPT_PIPEWAIT, Clong(1))
Curl.setopt(easy, CURLOPT_POST, Clong(1))
Curl.setopt(easy, CURLOPT_HTTPHEADER, GRPC_STATIC_HEADERS[])
if !revocation
Curl.setopt(easy, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE)
end
if maxage > 0
Curl.setopt(easy, CURLOPT_MAXAGE_CONN, maxage)
end
Expand Down Expand Up @@ -106,10 +114,12 @@ end
function grpc_request(downloader::Downloader, url::String, input::Channel{T1}, output::Channel{T2};
maxage::Clong = typemax(Clong),
keepalive::Clong = 60,
negotiation::Symbol = :http2_prior_knowledge,
revocation::Bool = true,
request_timeout::Real = Inf,
connect_timeout::Real = 0,
verbose::Bool = false)::gRPCStatus where {T1 <: ProtoType, T2 <: ProtoType}
Curl.with_handle(easy_handle(maxage, keepalive)) do easy
Curl.with_handle(easy_handle(maxage, keepalive, negotiation, revocation)) do easy
# setup the request
Curl.set_url(easy, url)
Curl.set_timeout(easy, request_timeout)
Expand All @@ -133,4 +143,4 @@ function grpc_request(downloader::Downloader, url::String, input::Channel{T1}, o

(easy.code == CURLE_OK) ? gRPCStatus(true, "") : gRPCStatus(false, Curl.get_curl_errstr(easy))
end
end
end
6 changes: 5 additions & 1 deletion src/generate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ function generate(proto::String; outdir::String=pwd())

# generate protobuf service
mkpath(outdir)
ProtoBuf.protoc(`-I=$protodir --julia_out=$outdir $proto`)
bindir = Sys.BINDIR
pathenv = string(ENV["PATH"], Sys.iswindows() ? ";" : ":", bindir)
withenv("PATH"=>pathenv) do
ProtoBuf.protoc(`-I=$protodir --julia_out=$outdir $proto`)
end

# include the generated code and detect service method names
generated_module = joinpath(outdir, "$(package).jl")
Expand Down
14 changes: 13 additions & 1 deletion src/grpc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ end
gRPCController(;
[ maxage::Int = 0, ]
[ keepalive::Int64 = 60, ]
[ negotiation::Symbol = :http2_prior_knowledge, ]
[ revocation::Bool = true, ]
[ request_timeout::Real = Inf, ]
[ connect_timeout::Real = 0, ]
[ verbose::Bool = false, ]
Expand All @@ -61,6 +63,10 @@ Contains settings to control the behavior of gRPC requests.
be reused (default 180 seconds, same as setting this to 0).
- `keepalive`: interval (seconds) in which to send TCP keepalive messages on
the connection (default 60 seconds).
- `negotiation`: how to negotiate HTTP2, can be one of `:http2_prior_knowledge`
(no negotiation, the default), `:http2_tls` (http2 upgrade but only over
tls), or `:http2` (http2 upgrade)
- `revocation`: whether to check for certificate recovation (default is true)
- `request_timeout`: request timeout (seconds)
- `connect_timeout`: connect timeout (seconds) (default is 300 seconds, same
as setting this to 0)
Expand All @@ -69,18 +75,22 @@ Contains settings to control the behavior of gRPC requests.
struct gRPCController <: ProtoRpcController
maxage::Clong
keepalive::Clong
negotiation::Symbol
revocation::Bool
request_timeout::Real
connect_timeout::Real
verbose::Bool

function gRPCController(;
maxage::Integer = 0,
keepalive::Integer = 60,
negotiation::Symbol = :http2_prior_knowledge,
revocation::Bool = true,
request_timeout::Real = Inf,
connect_timeout::Real = 0,
verbose::Bool = false
)
new(maxage, keepalive, request_timeout, connect_timeout, verbose)
new(maxage, keepalive, negotiation, revocation, request_timeout, connect_timeout, verbose)
end
end

Expand Down Expand Up @@ -141,6 +151,8 @@ function call_method(channel::gRPCChannel, service::ServiceDescriptor, method::M
status_future = @async grpc_request(channel.downloader, url, input, outchannel;
maxage = controller.maxage,
keepalive = controller.keepalive,
negotiation = controller.negotiation,
revocation = controller.revocation,
request_timeout = controller.request_timeout,
connect_timeout = controller.connect_timeout,
verbose = controller.verbose,
Expand Down
1 change: 1 addition & 0 deletions test/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
grpc-go
server.pid
runserver_*
1 change: 0 additions & 1 deletion test/RouteGuideClients/.gitignore

This file was deleted.

79 changes: 79 additions & 0 deletions test/RouteGuideClients/RouteGuideClients.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
module RouteGuideClients
using gRPCClient

include("routeguide.jl")
using .routeguide

import Base: show
export RouteGuideBlockingClient, RouteGuideClient

struct RouteGuideBlockingClient
controller::gRPCController
channel::gRPCChannel
stub::RouteGuideBlockingStub

function RouteGuideBlockingClient(api_base_url::String; kwargs...)
controller = gRPCController(; kwargs...)
channel = gRPCChannel(api_base_url)
stub = RouteGuideBlockingStub(channel)
new(controller, channel, stub)
end
end

struct RouteGuideClient
controller::gRPCController
channel::gRPCChannel
stub::RouteGuideStub

function RouteGuideClient(api_base_url::String; kwargs...)
controller = gRPCController(; kwargs...)
channel = gRPCChannel(api_base_url)
stub = RouteGuideStub(channel)
new(controller, channel, stub)
end
end

show(io::IO, client::RouteGuideBlockingClient) = print(io, "RouteGuideBlockingClient(", client.channel.baseurl, ")")
show(io::IO, client::RouteGuideClient) = print(io, "RouteGuideClient(", client.channel.baseurl, ")")

import .routeguide: GetFeature
"""
GetFeature

- input: routeguide.Point
- output: routeguide.Feature
"""
GetFeature(client::RouteGuideBlockingClient, inp::routeguide.Point) = GetFeature(client.stub, client.controller, inp)
GetFeature(client::RouteGuideClient, inp::routeguide.Point, done::Function) = GetFeature(client.stub, client.controller, inp, done)

import .routeguide: ListFeatures
"""
ListFeatures

- input: routeguide.Rectangle
- output: Channel{routeguide.Feature}
"""
ListFeatures(client::RouteGuideBlockingClient, inp::routeguide.Rectangle) = ListFeatures(client.stub, client.controller, inp)
ListFeatures(client::RouteGuideClient, inp::routeguide.Rectangle, done::Function) = ListFeatures(client.stub, client.controller, inp, done)

import .routeguide: RecordRoute
"""
RecordRoute

- input: Channel{routeguide.Point}
- output: routeguide.RouteSummary
"""
RecordRoute(client::RouteGuideBlockingClient, inp::Channel{routeguide.Point}) = RecordRoute(client.stub, client.controller, inp)
RecordRoute(client::RouteGuideClient, inp::Channel{routeguide.Point}, done::Function) = RecordRoute(client.stub, client.controller, inp, done)

import .routeguide: RouteChat
"""
RouteChat

- input: Channel{routeguide.RouteNote}
- output: Channel{routeguide.RouteNote}
"""
RouteChat(client::RouteGuideBlockingClient, inp::Channel{routeguide.RouteNote}) = RouteChat(client.stub, client.controller, inp)
RouteChat(client::RouteGuideClient, inp::Channel{routeguide.RouteNote}, done::Function) = RouteChat(client.stub, client.controller, inp, done)

end # module RouteGuideClients
Loading