本文整理汇总了Golang中google/golang.org/grpc.WithDialer函数的典型用法代码示例。如果您正苦于以下问题:Golang WithDialer函数的具体用法?Golang WithDialer怎么用?Golang WithDialer使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了WithDialer函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: setUp
func setUp(hs *health.HealthServer, maxStream uint32, ua string, e env) (s *grpc.Server, cc *grpc.ClientConn) {
sopts := []grpc.ServerOption{grpc.MaxConcurrentStreams(maxStream)}
la := ":0"
switch e.network {
case "unix":
la = "/tmp/testsock" + fmt.Sprintf("%d", time.Now())
syscall.Unlink(la)
}
lis, err := net.Listen(e.network, la)
if err != nil {
grpclog.Fatalf("Failed to listen: %v", err)
}
if e.security == "tls" {
creds, err := credentials.NewServerTLSFromFile(tlsDir+"server1.pem", tlsDir+"server1.key")
if err != nil {
grpclog.Fatalf("Failed to generate credentials %v", err)
}
sopts = append(sopts, grpc.Creds(creds))
}
s = grpc.NewServer(sopts...)
if hs != nil {
healthpb.RegisterHealthCheckServer(s, hs)
}
testpb.RegisterTestServiceServer(s, &testServer{})
go s.Serve(lis)
addr := la
switch e.network {
case "unix":
default:
_, port, err := net.SplitHostPort(lis.Addr().String())
if err != nil {
grpclog.Fatalf("Failed to parse listener address: %v", err)
}
addr = "localhost:" + port
}
if e.security == "tls" {
creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "x.test.youtube.com")
if err != nil {
grpclog.Fatalf("Failed to create credentials %v", err)
}
cc, err = grpc.Dial(addr, grpc.WithTransportCredentials(creds), grpc.WithDialer(e.dialer), grpc.WithUserAgent(ua))
} else {
cc, err = grpc.Dial(addr, grpc.WithDialer(e.dialer), grpc.WithUserAgent(ua))
}
if err != nil {
grpclog.Fatalf("Dial(%q) = %v", addr, err)
}
return
}
开发者ID:ELMERzark,项目名称:grpc-go,代码行数:49,代码来源:end2end_test.go
示例2: init
func init() {
appengineDialerHook = func(ctx context.Context) grpc.DialOption {
return grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
return socket.DialTimeout(ctx, "tcp", addr, timeout)
})
}
}
开发者ID:Ropes,项目名称:pubbing,代码行数:7,代码来源:dial_appengine.go
示例3: setUpSignerClient
func setUpSignerClient(t *testing.T, grpcServer *grpc.Server) (*client.NotarySigner, *grpc.ClientConn, func()) {
socketFile, err := ioutil.TempFile("", "notary-grpc-test")
require.NoError(t, err)
socketFile.Close()
os.Remove(socketFile.Name())
lis, err := net.Listen("unix", socketFile.Name())
require.NoError(t, err, "unable to open socket to listen")
go grpcServer.Serve(lis)
// client setup
clientConn, err := grpc.Dial(socketFile.Name(), grpc.WithInsecure(), grpc.WithDialer(socketDialer))
require.NoError(t, err, "unable to connect to socket as a GRPC client")
signerClient := client.NewNotarySigner(clientConn)
cleanup := func() {
clientConn.Close()
grpcServer.Stop()
os.Remove(socketFile.Name())
}
return signerClient, clientConn, cleanup
}
开发者ID:jfrazelle,项目名称:notary,代码行数:25,代码来源:rpc_and_client_test.go
示例4: refreshRequestForwardingConnection
// refreshRequestForwardingConnection ensures that the client/transport are
// alive and that the current active address value matches the most
// recently-known address.
func (c *Core) refreshRequestForwardingConnection(clusterAddr string) error {
c.requestForwardingConnectionLock.Lock()
defer c.requestForwardingConnectionLock.Unlock()
// It's nil but we don't have an address anyways, so exit
if c.requestForwardingConnection == nil && clusterAddr == "" {
return nil
}
// NOTE: We don't fast path the case where we have a connection because the
// address is the same, because the cert/key could have changed if the
// active node ended up being the same node. Before we hit this function in
// Leader() we'll have done a hash on the advertised info to ensure that we
// won't hit this function unnecessarily anyways.
// Disabled, potentially, so clean up anything that might be around.
if clusterAddr == "" {
c.clearForwardingClients()
return nil
}
clusterURL, err := url.Parse(clusterAddr)
if err != nil {
c.logger.Error("core/refreshRequestForwardingConnection: error parsing cluster address", "error", err)
return err
}
switch os.Getenv("VAULT_USE_GRPC_REQUEST_FORWARDING") {
case "":
// Set up normal HTTP forwarding handling
tlsConfig, err := c.ClusterTLSConfig()
if err != nil {
c.logger.Error("core/refreshRequestForwardingConnection: error fetching cluster tls configuration", "error", err)
return err
}
tp := &http2.Transport{
TLSClientConfig: tlsConfig,
}
c.requestForwardingConnection = &activeConnection{
transport: tp,
clusterAddr: clusterAddr,
}
default:
// Set up grpc forwarding handling
// It's not really insecure, but we have to dial manually to get the
// ALPN header right. It's just "insecure" because GRPC isn't managing
// the TLS state.
ctx, cancelFunc := context.WithCancel(context.Background())
c.rpcClientConnCancelFunc = cancelFunc
c.rpcClientConn, err = grpc.DialContext(ctx, clusterURL.Host, grpc.WithDialer(c.getGRPCDialer()), grpc.WithInsecure())
if err != nil {
c.logger.Error("core/refreshRequestForwardingConnection: err setting up rpc client", "error", err)
return err
}
c.rpcForwardingClient = NewRequestForwardingClient(c.rpcClientConn)
}
return nil
}
开发者ID:quixoten,项目名称:vault,代码行数:63,代码来源:request_forwarding.go
示例5: initManagerConnection
func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{}) error {
opts := []grpc.DialOption{}
insecureCreds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
opts = append(opts, grpc.WithTransportCredentials(insecureCreds))
// Using listen address instead of advertised address because this is a
// local connection.
addr := n.config.ListenControlAPI
opts = append(opts, grpc.WithDialer(
func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", addr, timeout)
}))
conn, err := grpc.Dial(addr, opts...)
if err != nil {
return err
}
state := grpc.Idle
for {
s, err := conn.WaitForStateChange(ctx, state)
if err != nil {
n.setControlSocket(nil)
return err
}
if s == grpc.Ready {
n.setControlSocket(conn)
if ready != nil {
close(ready)
ready = nil
}
} else if state == grpc.Shutdown {
n.setControlSocket(nil)
}
state = s
}
}
开发者ID:Chandra-TechPassionate,项目名称:docker,代码行数:34,代码来源:node.go
示例6: DialGRPC
func (l *service) DialGRPC() (*grpc.ClientConn, error) {
if l.socketAddr == "" {
return nil, errors.New("socket address is empty. Is the service started?")
}
log.Println("dialing server")
return grpc.Dial(l.socketAddr, grpc.WithDialer(dialer()), grpc.WithInsecure())
}
开发者ID:axw,项目名称:lingo,代码行数:7,代码来源:service.go
示例7: initManagerConnection
func (n *Node) initManagerConnection(ctx context.Context, ready chan<- struct{}) error {
opts := []grpc.DialOption{}
insecureCreds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
opts = append(opts, grpc.WithTransportCredentials(insecureCreds))
// Using listen address instead of advertised address because this is a
// local connection.
addr := n.config.ListenControlAPI
opts = append(opts, grpc.WithDialer(
func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", addr, timeout)
}))
conn, err := grpc.Dial(addr, opts...)
if err != nil {
return err
}
client := api.NewHealthClient(conn)
for {
resp, err := client.Check(ctx, &api.HealthCheckRequest{Service: "ControlAPI"})
if err != nil {
return err
}
if resp.Status == api.HealthCheckResponse_SERVING {
break
}
time.Sleep(500 * time.Millisecond)
}
n.setControlSocket(conn)
if ready != nil {
close(ready)
}
return nil
}
开发者ID:Mic92,项目名称:docker,代码行数:32,代码来源:node.go
示例8: dialSetupOpts
// dialSetupOpts gives the dial opts prior to any authentication
func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts []grpc.DialOption) {
if c.cfg.DialTimeout > 0 {
opts = []grpc.DialOption{grpc.WithTimeout(c.cfg.DialTimeout)}
}
opts = append(opts, dopts...)
f := func(host string, t time.Duration) (net.Conn, error) {
proto, host, _ := parseEndpoint(c.balancer.getEndpoint(host))
if proto == "" {
return nil, fmt.Errorf("unknown scheme for %q", host)
}
select {
case <-c.ctx.Done():
return nil, c.ctx.Err()
default:
}
return net.DialTimeout(proto, host, t)
}
opts = append(opts, grpc.WithDialer(f))
creds := c.creds
if _, _, scheme := parseEndpoint(endpoint); len(scheme) != 0 {
creds = c.processCreds(scheme)
}
if creds != nil {
opts = append(opts, grpc.WithTransportCredentials(*creds))
} else {
opts = append(opts, grpc.WithInsecure())
}
return opts
}
开发者ID:RichardKnop,项目名称:go-oauth2-server,代码行数:33,代码来源:client.go
示例9: Dial
// Dial establishes a connection for a given endpoint using the client's config
func (c *Client) Dial(endpoint string) (*grpc.ClientConn, error) {
opts := []grpc.DialOption{
grpc.WithBlock(),
grpc.WithTimeout(c.cfg.DialTimeout),
}
if c.creds != nil {
opts = append(opts, grpc.WithTransportCredentials(*c.creds))
} else {
opts = append(opts, grpc.WithInsecure())
}
proto := "tcp"
if url, uerr := url.Parse(endpoint); uerr == nil && url.Scheme == "unix" {
proto = "unix"
// strip unix:// prefix so certs work
endpoint = url.Host
}
f := func(a string, t time.Duration) (net.Conn, error) {
select {
case <-c.ctx.Done():
return nil, c.ctx.Err()
default:
}
return net.DialTimeout(proto, a, t)
}
opts = append(opts, grpc.WithDialer(f))
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return nil, err
}
return conn, nil
}
开发者ID:oywc410,项目名称:MYPG,代码行数:34,代码来源:client.go
示例10: SetUpSuite
func (s *testBinlogSuite) SetUpSuite(c *C) {
logLevel := os.Getenv("log_level")
log.SetLevelByString(logLevel)
store, err := tikv.NewMockTikvStore()
c.Assert(err, IsNil)
s.store = store
tidb.SetSchemaLease(0)
s.unixFile = "/tmp/mock-binlog-pump"
os.Remove(s.unixFile)
l, err := net.Listen("unix", s.unixFile)
c.Assert(err, IsNil)
s.serv = grpc.NewServer()
s.pump = new(mockBinlogPump)
binlog.RegisterPumpServer(s.serv, s.pump)
go s.serv.Serve(l)
opt := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", addr, timeout)
})
clientCon, err := grpc.Dial(s.unixFile, opt, grpc.WithInsecure())
c.Assert(err, IsNil)
c.Assert(clientCon, NotNil)
binloginfo.PumpClient = binlog.NewPumpClient(clientCon)
s.tk = testkit.NewTestKit(c, s.store)
s.tk.MustExec("use test")
domain := sessionctx.GetDomain(s.tk.Se.(context.Context))
s.ddl = domain.DDL()
}
开发者ID:pingcap,项目名称:tidb,代码行数:27,代码来源:binloginfo_test.go
示例11: clientSetUp
func clientSetUp(t *testing.T, addr string, cg grpc.CompressorGenerator, dg grpc.DecompressorGenerator, ua string, e env) (cc *grpc.ClientConn) {
var derr error
if e.security == "tls" {
creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "x.test.youtube.com")
if err != nil {
t.Fatalf("Failed to create credentials %v", err)
}
cc, derr = grpc.Dial(addr, grpc.WithTransportCredentials(creds), grpc.WithDialer(e.dialer), grpc.WithUserAgent(ua), grpc.WithCompressor(cg), grpc.WithDecompressor(dg))
} else {
cc, derr = grpc.Dial(addr, grpc.WithDialer(e.dialer), grpc.WithInsecure(), grpc.WithUserAgent(ua), grpc.WithCompressor(cg), grpc.WithDecompressor(dg))
}
if derr != nil {
t.Fatalf("Dial(%q) = %v", addr, derr)
}
return
}
开发者ID:slafgod000,项目名称:grpc-go,代码行数:16,代码来源:end2end_test.go
示例12: OnStart
func (cli *grpcClient) OnStart() error {
cli.QuitService.OnStart()
RETRY_LOOP:
for {
conn, err := grpc.Dial(cli.addr, grpc.WithInsecure(), grpc.WithDialer(dialerFunc))
if err != nil {
if cli.mustConnect {
return err
} else {
log.Warn(Fmt("tmsp.grpcClient failed to connect to %v. Retrying...\n", cli.addr))
time.Sleep(time.Second * 3)
continue RETRY_LOOP
}
}
client := types.NewTMSPApplicationClient(conn)
ENSURE_CONNECTED:
for {
_, err := client.Echo(context.Background(), &types.RequestEcho{"hello"}, grpc.FailFast(true))
if err == nil {
break ENSURE_CONNECTED
}
time.Sleep(time.Second)
}
cli.client = client
return nil
}
}
开发者ID:tendermint,项目名称:tmsp,代码行数:31,代码来源:grpc_client.go
示例13: getClient
// getClient returns a connection to the Suite containerd
func (cs *ContainerdSuite) getClient(socket string) error {
// Parse proto://address form addresses.
bindParts := strings.SplitN(socket, "://", 2)
if len(bindParts) != 2 {
return fmt.Errorf("bad bind address format %s, expected proto://address", socket)
}
// reset the logger for grpc to log to dev/null so that it does not mess with our stdio
grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
dialOpts := []grpc.DialOption{grpc.WithInsecure()}
dialOpts = append(dialOpts,
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout(bindParts[0], bindParts[1], timeout)
}),
grpc.WithBlock(),
grpc.WithTimeout(5*time.Second),
)
conn, err := grpc.Dial(socket, dialOpts...)
if err != nil {
return err
}
healthClient := grpc_health_v1.NewHealthClient(conn)
if _, err := healthClient.Check(context.Background(), &grpc_health_v1.HealthCheckRequest{}); err != nil {
return err
}
cs.grpcClient = types.NewAPIClient(conn)
return nil
}
开发者ID:estesp,项目名称:containerd,代码行数:30,代码来源:check_test.go
示例14: setUp
func setUp(maxStream uint32, e env) (s *grpc.Server, cc *grpc.ClientConn) {
s = grpc.NewServer(grpc.MaxConcurrentStreams(maxStream))
la := ":0"
switch e.network {
case "unix":
la = "/tmp/testsock" + fmt.Sprintf("%p", s)
syscall.Unlink(la)
}
lis, err := net.Listen(e.network, la)
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
testpb.RegisterTestServiceServer(s, &testServer{})
if e.security == "tls" {
creds, err := credentials.NewServerTLSFromFile(tlsDir+"server1.pem", tlsDir+"server1.key")
if err != nil {
log.Fatalf("Failed to generate credentials %v", err)
}
go s.Serve(creds.NewListener(lis))
} else {
go s.Serve(lis)
}
addr := la
switch e.network {
case "unix":
default:
_, port, err := net.SplitHostPort(lis.Addr().String())
if err != nil {
log.Fatalf("Failed to parse listener address: %v", err)
}
addr = "localhost:" + port
}
if e.security == "tls" {
creds, err := credentials.NewClientTLSFromFile(tlsDir+"ca.pem", "x.test.youtube.com")
if err != nil {
log.Fatalf("Failed to create credentials %v", err)
}
cc, err = grpc.Dial(addr, grpc.WithTransportCredentials(creds), grpc.WithDialer(e.dialer))
} else {
cc, err = grpc.Dial(addr, grpc.WithDialer(e.dialer))
}
if err != nil {
log.Fatalf("Dial(%q) = %v", addr, err)
}
return
}
开发者ID:progrium,项目名称:notary,代码行数:46,代码来源:end2end_test.go
示例15: NewDialer
func NewDialer() grpc.DialOption {
return grpc.WithDialer(func(addr string, _ time.Duration) (net.Conn, error) {
conn, err := websocket.Dial(addr, "ws", "localhost")
if err != nil {
return nil, err
}
return conn, nil
})
}
开发者ID:limbo-services,项目名称:core,代码行数:9,代码来源:ws.go
示例16: setupRaftLogCluster
// raft replicas are numbered 1..n and reside in array indices 0..n-1
// A copy of this function exists in raftlog_test.go
func setupRaftLogCluster(t *testing.T, nReplicas, nStandbys int) (ret []replication.LogReplicator, dbs []kv.DB, clks []*clock.Mock, nw *nettestutil.Network, teardown func()) {
m := nReplicas
n := nReplicas + nStandbys
replicaIDs := make([]uint64, 0, n)
for i := uint64(0); i < uint64(n); i++ {
replicaIDs = append(replicaIDs, 1+i)
}
addrs := make([]string, 0, n)
nw = nettestutil.New(n)
lookupDialerFrom := func(src int) func(uint64) raftproto.RaftClient {
return func(dstPlus1 uint64) raftproto.RaftClient {
cc, err := grpc.Dial(addrs[dstPlus1-1], grpc.WithInsecure(), grpc.WithDialer(
func(addr string, timeout time.Duration) (net.Conn, error) {
nc, err := net.DialTimeout("tcp", addr, timeout)
return nw.Wrap(nc, src, int(dstPlus1-1)), err
}))
if err != nil {
panic(err) // async dial should not err
}
return raftproto.NewRaftClient(cc)
}
}
teardown = func() {}
for i := 0; i < n; i++ {
clk := clock.NewMock()
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
s := grpc.NewServer()
db, dbDown := setupDB(t)
dbs = append(dbs, db)
l := raftlog.New(
uint64(i+1), replicaIDs[:m],
db, nil,
clk, tick,
s, lookupDialerFrom(i),
)
go s.Serve(ln)
ret = append(ret, l)
clks = append(clks, clk)
addrs = append(addrs, ln.Addr().String())
teardown = chain(func() { s.Stop(); ln.Close(); l.Stop() }, dbDown, teardown)
}
for _, l := range ret {
go func(l replication.LogReplicator) {
for _ = range l.LeaderHintSet() {
}
}(l)
}
return ret, dbs, clks, nw, teardown
}
开发者ID:Liamsi,项目名称:coname,代码行数:58,代码来源:server_test.go
示例17: createBinlogClient
func createBinlogClient() {
dialerOpt := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", addr, timeout)
})
clientCon, err := grpc.Dial(*binlogSocket, dialerOpt, grpc.WithInsecure())
if err != nil {
log.Fatal(errors.ErrorStack(err))
}
binloginfo.PumpClient = binlog.NewPumpClient(clientCon)
}
开发者ID:pingcap,项目名称:tidb,代码行数:10,代码来源:main.go
示例18: controlDial
func (b *bazil) controlDial() {
b.control.conn, b.control.err = grpc.Dial(
filepath.Join(b.Config.DataDir.String(), "control"),
grpc.WithTimeout(500*time.Millisecond),
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", addr, timeout)
}),
)
b.control.client = wire.NewControlClient(b.control.conn)
}
开发者ID:read-later,项目名称:bazil,代码行数:10,代码来源:cli.go
示例19: New
// New creates a fresh instance of libcontainerd remote.
func New(stateDir string, options ...RemoteOption) (_ Remote, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("Failed to connect to containerd. Please make sure containerd is installed in your PATH or you have specificed the correct address. Got error: %v", err)
}
}()
r := &remote{
stateDir: stateDir,
daemonPid: -1,
eventTsPath: filepath.Join(stateDir, eventTimestampFilename),
pastEvents: make(map[string]*containerd.Event),
}
for _, option := range options {
if err := option.Apply(r); err != nil {
return nil, err
}
}
if err := sysinfo.MkdirAll(stateDir, 0700); err != nil {
return nil, err
}
if r.rpcAddr == "" {
r.rpcAddr = filepath.Join(stateDir, containerdSockFilename)
}
if r.startDaemon {
if err := r.runContainerdDaemon(); err != nil {
return nil, err
}
}
// don't output the grpc reconnect logging
grpclog.SetLogger(log.New(ioutil.Discard, "", log.LstdFlags))
dialOpts := append([]grpc.DialOption{grpc.WithInsecure()},
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout("unix", addr, timeout)
}),
)
conn, err := grpc.Dial(r.rpcAddr, dialOpts...)
if err != nil {
return nil, fmt.Errorf("error connecting to containerd: %v", err)
}
r.rpcConn = conn
r.apiClient = containerd.NewAPIClient(conn)
go r.handleConnectionChange()
if err := r.startEventsMonitor(); err != nil {
return nil, err
}
return r, nil
}
开发者ID:ungureanuvladvictor,项目名称:docker,代码行数:56,代码来源:remote_linux.go
示例20: updateKEK
func (m *Manager) updateKEK(ctx context.Context, cluster *api.Cluster) error {
securityConfig := m.config.SecurityConfig
nodeID := m.config.SecurityConfig.ClientTLSCreds.NodeID()
logger := log.G(ctx).WithFields(logrus.Fields{
"node.id": nodeID,
"node.role": ca.ManagerRole,
})
kekData := ca.KEKData{Version: cluster.Meta.Version.Index}
for _, encryptionKey := range cluster.UnlockKeys {
if encryptionKey.Subsystem == ca.ManagerRole {
kekData.KEK = encryptionKey.Key
break
}
}
updated, unlockedToLocked, err := m.dekRotator.MaybeUpdateKEK(kekData)
if err != nil {
logger.WithError(err).Errorf("failed to re-encrypt TLS key with a new KEK")
return err
}
if updated {
logger.Debug("successfully rotated KEK")
}
if unlockedToLocked {
// a best effort attempt to update the TLS certificate - if it fails, it'll be updated the next time it renews;
// don't wait because it might take a bit
go func() {
insecureCreds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})
conn, err := grpc.Dial(
m.config.ControlAPI,
grpc.WithTransportCredentials(insecureCreds),
grpc.WithDialer(
func(addr string, timeout time.Duration) (net.Conn, error) {
return xnet.DialTimeoutLocal(addr, timeout)
}),
)
if err != nil {
logger.WithError(err).Error("failed to connect to local manager socket after locking the cluster")
return
}
defer conn.Close()
connBroker := connectionbroker.New(remotes.NewRemotes())
connBroker.SetLocalConn(conn)
if err := ca.RenewTLSConfigNow(ctx, securityConfig, connBroker); err != nil {
logger.WithError(err).Error("failed to download new TLS certificate after locking the cluster")
}
}()
}
return nil
}
开发者ID:docker,项目名称:docker,代码行数:53,代码来源:manager.go
注:本文中的google/golang.org/grpc.WithDialer函数示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论