func NewChannel()

in channel.go [233:360]


func NewChannel(serviceName string, opts *ChannelOptions) (*Channel, error) {
	if serviceName == "" {
		return nil, ErrNoServiceName
	}

	if opts == nil {
		opts = &ChannelOptions{}
	}

	processName := opts.ProcessName
	if processName == "" {
		processName = fmt.Sprintf("%s[%d]", filepath.Base(os.Args[0]), os.Getpid())
	}

	logger := opts.Logger
	if logger == nil {
		logger = NullLogger
	}

	statsReporter := opts.StatsReporter
	if statsReporter == nil {
		statsReporter = NullStatsReporter
	}

	timeNow := opts.TimeNow
	if timeNow == nil {
		timeNow = time.Now
	}

	timeTicker := opts.TimeTicker
	if timeTicker == nil {
		timeTicker = time.NewTicker
	}

	chID := _nextChID.Inc()
	logger = logger.WithFields(
		LogField{"serviceName", serviceName},
		LogField{"process", processName},
		LogField{"chID", chID},
	)

	if err := opts.validateIdleCheck(); err != nil {
		return nil, err
	}

	// Default to dialContext if dialer is not passed in as an option
	dialCtx := dialContext
	if opts.Dialer != nil {
		dialCtx = func(ctx context.Context, hostPort string) (net.Conn, error) {
			return opts.Dialer(ctx, "tcp", hostPort)
		}
	}

	if opts.ConnContext == nil {
		opts.ConnContext = func(ctx context.Context, conn net.Conn) context.Context {
			return ctx
		}
	}

	ch := &Channel{
		channelConnectionCommon: channelConnectionCommon{
			log:           logger,
			relayLocal:    toStringSet(opts.RelayLocalHandlers),
			statsReporter: statsReporter,
			subChannels:   &subChannelMap{},
			timeNow:       timeNow,
			timeTicker:    timeTicker,
			tracer:        opts.Tracer,
		},
		chID:                chID,
		connectionOptions:   opts.DefaultConnectionOptions.withDefaults(),
		relayHost:           opts.RelayHost,
		relayMaxTimeout:     validateRelayMaxTimeout(opts.RelayMaxTimeout, logger),
		relayMaxConnTimeout: opts.RelayMaxConnectionTimeout,
		relayMaxTombs:       opts.RelayMaxTombs,
		relayTimerVerify:    opts.RelayTimerVerification,
		dialer:              dialCtx,
		connContext:         opts.ConnContext,
		closed:              make(chan struct{}),
	}
	ch.peers = newRootPeerList(ch, opts.OnPeerStatusChanged).newChild()

	switch {
	case len(opts.SkipHandlerMethods) > 0 && opts.Handler != nil:
		sm, err := toServiceMethodSet(opts.SkipHandlerMethods)
		if err != nil {
			return nil, err
		}
		ch.handler = userHandlerWithSkip{
			localHandler:      channelHandler{ch},
			ignoreUserHandler: sm,
			userHandler:       opts.Handler,
		}
	case opts.Handler != nil:
		ch.handler = opts.Handler
	default:
		ch.handler = channelHandler{ch}
	}

	ch.mutable.peerInfo = LocalPeerInfo{
		PeerInfo: PeerInfo{
			ProcessName: processName,
			HostPort:    ephemeralHostPort,
			IsEphemeral: true,
			Version: PeerVersion{
				Language:        "go",
				LanguageVersion: strings.TrimPrefix(runtime.Version(), "go"),
				TChannelVersion: VersionInfo,
			},
		},
		ServiceName: serviceName,
	}
	ch.mutable.state = ChannelClient
	ch.mutable.conns = make(map[uint32]*Connection)
	ch.createCommonStats()
	ch.internalHandlers = ch.createInternalHandlers()

	registerNewChannel(ch)

	if opts.RelayHost != nil {
		opts.RelayHost.SetChannel(ch)
	}

	// Start the idle connection timer.
	ch.mutable.idleSweep = startIdleSweep(ch, opts)

	return ch, nil
}