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
}