channel.go
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
	}

	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),
		relayTimerVerify:  opts.RelayTimerVerification,
		closed:            make(chan struct{}),
	}
	ch.peers = newRootPeerList(ch, opts.OnPeerStatusChanged).newChild()

	if opts.Handler != nil {
		ch.handler = opts.Handler
	} else {
		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()

	// Register internal unless the root handler has been overridden, since
	// Register will panic.
	if opts.Handler == nil {
		ch.registerInternal()
	}

	registerNewChannel(ch)

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

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

	return ch, nil
}
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
	}

	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),
		relayTimerVerify:  opts.RelayTimerVerification,
		closed:            make(chan struct{}),
	}
	ch.peers = newRootPeerList(ch, opts.OnPeerStatusChanged).newChild()

	if opts.Handler != nil {
		ch.handler = opts.Handler
	} else {
		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()

	// Register internal unless the root handler has been overridden, since
	// Register will panic.
	if opts.Handler == nil {
		ch.registerInternal()
	}

	registerNewChannel(ch)

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

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

	return ch, nil
}
// NewChannel creates a new Channel.  The new channel can be used to send outbound requests
// to peers, but will not listen or handling incoming requests until one of ListenAndServe
// or Serve is called. The local service name should be passed to serviceName.