mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 23:49:57 +00:00
TUN-528: Move cloudflared into a separate repo
This commit is contained in:
23
vendor/zombiezen.com/go/capnproto2/server/BUILD.bazel
generated
vendored
Normal file
23
vendor/zombiezen.com/go/capnproto2/server/BUILD.bazel
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["server.go"],
|
||||
importpath = "zombiezen.com/go/capnproto2/server",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//:go_default_library",
|
||||
"//internal/fulfiller:go_default_library",
|
||||
"@org_golang_x_net//context:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["server_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//internal/aircraftlib:go_default_library",
|
||||
"@org_golang_x_net//context:go_default_library",
|
||||
],
|
||||
)
|
231
vendor/zombiezen.com/go/capnproto2/server/server.go
generated
vendored
Normal file
231
vendor/zombiezen.com/go/capnproto2/server/server.go
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
// Package server provides runtime support for implementing Cap'n Proto
|
||||
// interfaces locally.
|
||||
package server // import "zombiezen.com/go/capnproto2/server"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"zombiezen.com/go/capnproto2"
|
||||
"zombiezen.com/go/capnproto2/internal/fulfiller"
|
||||
)
|
||||
|
||||
// A Method describes a single method on a server object.
|
||||
type Method struct {
|
||||
capnp.Method
|
||||
Impl Func
|
||||
ResultsSize capnp.ObjectSize
|
||||
}
|
||||
|
||||
// A Func is a function that implements a single method.
|
||||
type Func func(ctx context.Context, options capnp.CallOptions, params, results capnp.Struct) error
|
||||
|
||||
// Closer is the interface that wraps the Close method.
|
||||
type Closer interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
// A server is a locally implemented interface.
|
||||
type server struct {
|
||||
methods sortedMethods
|
||||
closer Closer
|
||||
queue chan *call
|
||||
stop chan struct{}
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// New returns a client that makes calls to a set of methods.
|
||||
// If closer is nil then the client's Close is a no-op. The server
|
||||
// guarantees message delivery order by blocking each call on the
|
||||
// return or acknowledgment of the previous call. See the Ack function
|
||||
// for more details.
|
||||
func New(methods []Method, closer Closer) capnp.Client {
|
||||
s := &server{
|
||||
methods: make(sortedMethods, len(methods)),
|
||||
closer: closer,
|
||||
queue: make(chan *call),
|
||||
stop: make(chan struct{}),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
copy(s.methods, methods)
|
||||
sort.Sort(s.methods)
|
||||
go s.dispatch()
|
||||
return s
|
||||
}
|
||||
|
||||
// dispatch runs in its own goroutine.
|
||||
func (s *server) dispatch() {
|
||||
defer close(s.done)
|
||||
for {
|
||||
select {
|
||||
case cl := <-s.queue:
|
||||
err := s.startCall(cl)
|
||||
if err != nil {
|
||||
cl.ans.Reject(err)
|
||||
}
|
||||
case <-s.stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// startCall runs in the dispatch goroutine to start a call.
|
||||
func (s *server) startCall(cl *call) error {
|
||||
_, out, err := capnp.NewMessage(capnp.SingleSegment(nil))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results, err := capnp.NewRootStruct(out, cl.method.ResultsSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
acksig := newAckSignal()
|
||||
opts := cl.Options.With([]capnp.CallOption{capnp.SetOptionValue(ackSignalKey, acksig)})
|
||||
go func() {
|
||||
err := cl.method.Impl(cl.Ctx, opts, cl.Params, results)
|
||||
if err == nil {
|
||||
cl.ans.Fulfill(results)
|
||||
} else {
|
||||
cl.ans.Reject(err)
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case <-acksig.c:
|
||||
case <-cl.ans.Done():
|
||||
// Implementation functions may not call Ack, which is fine for
|
||||
// smaller functions.
|
||||
case <-cl.Ctx.Done():
|
||||
// Ideally, this would reject the answer immediately, but then you
|
||||
// would race with the implementation function.
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) Call(cl *capnp.Call) capnp.Answer {
|
||||
sm := s.methods.find(&cl.Method)
|
||||
if sm == nil {
|
||||
return capnp.ErrorAnswer(&capnp.MethodError{
|
||||
Method: &cl.Method,
|
||||
Err: capnp.ErrUnimplemented,
|
||||
})
|
||||
}
|
||||
cl, err := cl.Copy(nil)
|
||||
if err != nil {
|
||||
return capnp.ErrorAnswer(err)
|
||||
}
|
||||
scall := newCall(cl, sm)
|
||||
select {
|
||||
case s.queue <- scall:
|
||||
return &scall.ans
|
||||
case <-s.stop:
|
||||
return capnp.ErrorAnswer(errClosed)
|
||||
case <-cl.Ctx.Done():
|
||||
return capnp.ErrorAnswer(cl.Ctx.Err())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) Close() error {
|
||||
close(s.stop)
|
||||
<-s.done
|
||||
if s.closer == nil {
|
||||
return nil
|
||||
}
|
||||
return s.closer.Close()
|
||||
}
|
||||
|
||||
// Ack acknowledges delivery of a server call, allowing other methods
|
||||
// to be called on the server. It is intended to be used inside the
|
||||
// implementation of a server function. Calling Ack on options that
|
||||
// aren't from a server method implementation is a no-op.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// func (my *myServer) MyMethod(call schema.MyServer_myMethod) error {
|
||||
// server.Ack(call.Options)
|
||||
// // ... do long-running operation ...
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// Ack need not be the first call in a function nor is it required.
|
||||
// Since the function's return is also an acknowledgment of delivery,
|
||||
// short functions can return without calling Ack. However, since
|
||||
// clients will not return an Answer until the delivery is acknowledged,
|
||||
// it is advisable to ack early.
|
||||
func Ack(opts capnp.CallOptions) {
|
||||
if ack, _ := opts.Value(ackSignalKey).(*ackSignal); ack != nil {
|
||||
ack.signal()
|
||||
}
|
||||
}
|
||||
|
||||
type call struct {
|
||||
*capnp.Call
|
||||
ans fulfiller.Fulfiller
|
||||
method *Method
|
||||
}
|
||||
|
||||
func newCall(cl *capnp.Call, sm *Method) *call {
|
||||
return &call{Call: cl, method: sm}
|
||||
}
|
||||
|
||||
type sortedMethods []Method
|
||||
|
||||
// find returns the method with the given ID or nil.
|
||||
func (sm sortedMethods) find(id *capnp.Method) *Method {
|
||||
i := sort.Search(len(sm), func(i int) bool {
|
||||
m := &sm[i]
|
||||
if m.InterfaceID != id.InterfaceID {
|
||||
return m.InterfaceID >= id.InterfaceID
|
||||
}
|
||||
return m.MethodID >= id.MethodID
|
||||
})
|
||||
if i == len(sm) {
|
||||
return nil
|
||||
}
|
||||
m := &sm[i]
|
||||
if m.InterfaceID != id.InterfaceID || m.MethodID != id.MethodID {
|
||||
return nil
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (sm sortedMethods) Len() int {
|
||||
return len(sm)
|
||||
}
|
||||
|
||||
func (sm sortedMethods) Less(i, j int) bool {
|
||||
if id1, id2 := sm[i].InterfaceID, sm[j].InterfaceID; id1 != id2 {
|
||||
return id1 < id2
|
||||
}
|
||||
return sm[i].MethodID < sm[j].MethodID
|
||||
}
|
||||
|
||||
func (sm sortedMethods) Swap(i, j int) {
|
||||
sm[i], sm[j] = sm[j], sm[i]
|
||||
}
|
||||
|
||||
type ackSignal struct {
|
||||
c chan struct{}
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func newAckSignal() *ackSignal {
|
||||
return &ackSignal{c: make(chan struct{})}
|
||||
}
|
||||
|
||||
func (ack *ackSignal) signal() {
|
||||
ack.once.Do(func() {
|
||||
close(ack.c)
|
||||
})
|
||||
}
|
||||
|
||||
// callOptionKey is the unexported key type for predefined options.
|
||||
type callOptionKey int
|
||||
|
||||
// Predefined call options
|
||||
const (
|
||||
ackSignalKey callOptionKey = iota + 1
|
||||
)
|
||||
|
||||
var errClosed = errors.New("capnp: server closed")
|
110
vendor/zombiezen.com/go/capnproto2/server/server_test.go
generated
vendored
Normal file
110
vendor/zombiezen.com/go/capnproto2/server/server_test.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
package server_test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
air "zombiezen.com/go/capnproto2/internal/aircraftlib"
|
||||
. "zombiezen.com/go/capnproto2/server"
|
||||
)
|
||||
|
||||
type echoImpl struct{}
|
||||
|
||||
func (echoImpl) Echo(call air.Echo_echo) error {
|
||||
in, err := call.Params.In()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
call.Results.SetOut(in + in)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestServerCall(t *testing.T) {
|
||||
echo := air.Echo_ServerToClient(echoImpl{})
|
||||
defer func() {
|
||||
if err := echo.Client.Close(); err != nil {
|
||||
t.Error("Close:", err)
|
||||
}
|
||||
}()
|
||||
|
||||
result, err := echo.Echo(context.Background(), func(p air.Echo_echo_Params) error {
|
||||
err := p.SetIn("foo")
|
||||
return err
|
||||
}).Struct()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("echo.Echo() error: %v", err)
|
||||
}
|
||||
if out, err := result.Out(); err != nil {
|
||||
t.Errorf("echo.Echo() error: %v", err)
|
||||
} else if out != "foofoo" {
|
||||
t.Errorf("echo.Echo() = %q; want %q", out, "foofoo")
|
||||
}
|
||||
}
|
||||
|
||||
type callSeq uint32
|
||||
|
||||
func (seq *callSeq) GetNumber(call air.CallSequence_getNumber) error {
|
||||
call.Results.SetN(uint32(*seq))
|
||||
*seq++
|
||||
return nil
|
||||
}
|
||||
|
||||
type lockCallSeq struct {
|
||||
n uint32
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (seq *lockCallSeq) GetNumber(call air.CallSequence_getNumber) error {
|
||||
seq.mu.Lock()
|
||||
defer seq.mu.Unlock()
|
||||
Ack(call.Options)
|
||||
|
||||
call.Results.SetN(seq.n)
|
||||
seq.n++
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestServerCallOrder(t *testing.T) {
|
||||
seq := air.CallSequence_ServerToClient(new(callSeq))
|
||||
testCallOrder(t, seq)
|
||||
if err := seq.Client.Close(); err != nil {
|
||||
t.Error("Close:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerCallOrderWithCustomLocks(t *testing.T) {
|
||||
seq := air.CallSequence_ServerToClient(new(lockCallSeq))
|
||||
testCallOrder(t, seq)
|
||||
if err := seq.Client.Close(); err != nil {
|
||||
t.Error("Close:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testCallOrder(t *testing.T, seq air.CallSequence) {
|
||||
ctx := context.Background()
|
||||
send := func() air.CallSequence_getNumber_Results_Promise {
|
||||
return seq.GetNumber(ctx, nil)
|
||||
}
|
||||
check := func(p air.CallSequence_getNumber_Results_Promise, n uint32) {
|
||||
result, err := p.Struct()
|
||||
if err != nil {
|
||||
t.Errorf("seq.getNumber() error: %v; want %d", err, n)
|
||||
} else if result.N() != n {
|
||||
t.Errorf("seq.getNumber() = %d; want %d", result.N(), n)
|
||||
}
|
||||
}
|
||||
|
||||
call0 := send()
|
||||
call1 := send()
|
||||
call2 := send()
|
||||
call3 := send()
|
||||
call4 := send()
|
||||
|
||||
check(call0, 0)
|
||||
check(call1, 1)
|
||||
check(call2, 2)
|
||||
check(call3, 3)
|
||||
check(call4, 4)
|
||||
}
|
Reference in New Issue
Block a user