func (c *Config) MspID(org string) (string, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return "", err
	}
	mspID := config.Organizations[strings.ToLower(org)].MspID
	if mspID == "" {
		return "", errors.Errorf("MSP ID is empty for org: %s", org)
	}
	return mspID, nil
}
MspID returns the MSP ID for the requested organization
package config
import (
	"bytes"
	"encoding/pem"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"path"
	"strings"
	"time"
	"github.com/spf13/viper"
	"github.com/hyperledger/fabric-sdk-go/api/apiconfig"
	"github.com/hyperledger/fabric-sdk-go/api/apilogging"
	"github.com/hyperledger/fabric-sdk-go/pkg/config/cryptoutil"
	"github.com/hyperledger/fabric-sdk-go/pkg/config/urlutil"
	"github.com/hyperledger/fabric-sdk-go/pkg/logging"
	lu "github.com/hyperledger/fabric-sdk-go/pkg/logging/utils"
	"github.com/pkg/errors"
	cs "github.com/hyperledger/fabric-sdk-go/pkg/cryptosuite"
	"github.com/hyperledger/fabric-sdk-go/internal/github.com/tjfoc/gmsm/sm2"
	tls "github.com/hyperledger/fabric-sdk-go/internal/github.com/tjfoc/gmtls"
)
var logger = logging.NewLogger(logModule)
const (
	cmdRoot        = "FABRIC_SDK"
	logModule      = "fabric_sdk_go"
	defaultTimeout = time.Second * 5
)
type Config struct {
	tlsCertPool         *sm2.CertPool
	networkConfig       *apiconfig.NetworkConfig
	networkConfigCached bool
	configViper         *viper.Viper
	opts                options
}
type options struct {
	envPrefix    string
	templatePath string
	template     *Config
}
type Option func(opts *options) error
func FromReader(in io.Reader, configType string, opts ...Option) apiconfig.ConfigProvider {
	return func() (apiconfig.Config, error) {
		c, err := newConfig(opts...)
		if err != nil {
			return nil, err
		}
		if configType == "" {
			return nil, errors.New("empty config type")
		}
		c.configViper.SetConfigType(configType)
		c.configViper.MergeConfig(in)
		return initConfig(c)
	}
}
func FromFile(name string, opts ...Option) apiconfig.ConfigProvider {
	return func() (apiconfig.Config, error) {
		c, err := newConfig(opts...)
		if err != nil {
			return nil, err
		}
		if name == "" {
			return nil, errors.New("filename is required")
		}
		c.configViper.SetConfigFile(name)
		err = c.configViper.MergeInConfig()
		if err == nil {
			logger.Debugf("Using config file: %s", c.configViper.ConfigFileUsed())
		} else {
			return nil, errors.Wrap(err, "loading config file failed")
		}
		return initConfig(c)
	}
}
func FromRaw(configBytes []byte, configType string, opts ...Option) apiconfig.ConfigProvider {
	buf := bytes.NewBuffer(configBytes)
	logger.Debugf("config.FromRaw buf Len is %d, Cap is %d: %s", buf.Len(), buf.Cap(), buf)
	return FromReader(buf, configType, opts...)
}
func WithEnvPrefix(prefix string) Option {
	return func(opts *options) error {
		opts.envPrefix = prefix
		return nil
	}
}
func newConfig(opts ...Option) (*Config, error) {
	o := options{
		envPrefix: cmdRoot,
	}
	for _, option := range opts {
		err := option(&o)
		if err != nil {
			return nil, errors.WithMessage(err, "Error in option passed to New")
		}
	}
	v := newViper(o.envPrefix)
	c := Config{
		configViper: v,
		opts:        o,
	}
	err := c.loadTemplateConfig()
	if err != nil {
		return nil, err
	}
	return &c, nil
}
func newViper(cmdRootPrefix string) *viper.Viper {
	myViper := viper.New()
	myViper.SetEnvPrefix(cmdRootPrefix)
	myViper.AutomaticEnv()
	replacer := strings.NewReplacer(".", "_")
	myViper.SetEnvKeyReplacer(replacer)
	return myViper
}
func initConfig(c *Config) (*Config, error) {
	setLogLevel(c.configViper)
	tlsCertPool, err := getCertPool(c.configViper)
	if err != nil {
		return nil, err
	}
	c.tlsCertPool = tlsCertPool
	if err = c.cacheNetworkConfiguration(); err != nil {
		return nil, errors.WithMessage(err, "network configuration load failed")
	}
	logger.Infof("config %s logging level is set to: %s", logModule, lu.LogLevelString(logging.GetLevel(logModule)))
	return c, nil
}
func getCertPool(myViper *viper.Viper) (*sm2.CertPool, error) {
	tlsCertPool := sm2.NewCertPool()
	if myViper.GetBool("client.tlsCerts.systemCertPool") == true {
		var err error
		if tlsCertPool, err = sm2.SystemCertPool(); err != nil {
			return nil, err
		}
		logger.Debugf("Loaded system cert pool of size: %d", len(tlsCertPool.Subjects()))
	}
	return tlsCertPool, nil
}
func setLogLevel(myViper *viper.Viper) {
	loggingLevelString := myViper.GetString("client.logging.level")
	logLevel := apilogging.DEBUG
	if loggingLevelString != "" {
		logger.Debugf("%s logging level from the config: %v", logModule, loggingLevelString)
		var err error
		logLevel, err = logging.LogLevel(loggingLevelString)
		if err != nil {
			panic(err)
		}
	}
	logging.SetLevel(logModule, logLevel)
}
func (c *Config) loadTemplateConfig() error {
	templatePath := c.opts.templatePath
	if templatePath == "" {
		return nil
	}
	c.configViper.AddConfigPath(substPathVars(templatePath))
	err := c.configViper.ReadInConfig()  
	if err != nil {                      
		return errors.Wrap(err, "loading config file failed")
	}
	return nil
}
func (c *Config) Client() (*apiconfig.ClientConfig, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return nil, err
	}
	client := config.Client
	client.TLSCerts.Path = substPathVars(client.TLSCerts.Path)
	client.TLSCerts.Client.Keyfile = substPathVars(client.TLSCerts.Client.Keyfile)
	client.TLSCerts.Client.Certfile = substPathVars(client.TLSCerts.Client.Certfile)
	return &client, nil
}
func (c *Config) CAConfig(org string) (*apiconfig.CAConfig, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return nil, err
	}
	caName, err := c.getCAName(org)
	if err != nil {
		return nil, err
	}
	caConfig := config.CertificateAuthorities[strings.ToLower(caName)]
	return &caConfig, nil
}
func (c *Config) CAServerCertPems(org string) ([]string, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return nil, err
	}
	caName, err := c.getCAName(org)
	if err != nil {
		return nil, err
	}
	if _, ok := config.CertificateAuthorities[strings.ToLower(caName)]; !ok {
		return nil, errors.Errorf("CA Server Name '%s' not found", caName)
	}
	certFilesPem := config.CertificateAuthorities[caName].TLSCACerts.Pem
	certPems := make([]string, len(certFilesPem))
	for i, v := range certFilesPem {
		certPems[i] = string(v)
	}
	return certPems, nil
}
func (c *Config) CAServerCertPaths(org string) ([]string, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return nil, err
	}
	caName, err := c.getCAName(org)
	if err != nil {
		return nil, err
	}
	if _, ok := config.CertificateAuthorities[strings.ToLower(caName)]; !ok {
		return nil, errors.Errorf("CA Server Name '%s' not found", caName)
	}
	certFiles := strings.Split(config.CertificateAuthorities[caName].TLSCACerts.Path, ",")
	certFileModPath := make([]string, len(certFiles))
	for i, v := range certFiles {
		certFileModPath[i] = substPathVars(v)
	}
	return certFileModPath, nil
}
func (c *Config) getCAName(org string) (string, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return "", err
	}
	logger.Debug("Getting cert authority for org: %s.", org)
	if len(config.Organizations[strings.ToLower(org)].CertificateAuthorities) == 0 {
		return "", errors.Errorf("organization %s has no Certificate Authorities setup. Make sure each org has at least 1 configured", org)
	}
	certAuthorityName := config.Organizations[strings.ToLower(org)].CertificateAuthorities[0]
	logger.Debugf("Cert authority for org: %s is %s", org, certAuthorityName)
	if certAuthorityName == "" {
		return "", errors.Errorf("certificate authority empty for %s. Make sure each org has at least 1 non empty certificate authority name", org)
	}
	return certAuthorityName, nil
}
func (c *Config) CAClientKeyPath(org string) (string, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return "", err
	}
	caName, err := c.getCAName(org)
	if err != nil {
		return "", err
	}
	if _, ok := config.CertificateAuthorities[strings.ToLower(caName)]; !ok {
		return "", errors.Errorf("CA Server Name '%s' not found", caName)
	}
	return substPathVars(config.CertificateAuthorities[strings.ToLower(caName)].TLSCACerts.Client.Keyfile), nil
}
func (c *Config) CAClientKeyPem(org string) (string, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return "", err
	}
	caName, err := c.getCAName(org)
	if err != nil {
		return "", err
	}
	if _, ok := config.CertificateAuthorities[strings.ToLower(caName)]; !ok {
		return "", errors.Errorf("CA Server Name '%s' not found", caName)
	}
	ca := config.CertificateAuthorities[strings.ToLower(caName)]
	if len(ca.TLSCACerts.Client.CertPem) == 0 {
		return "", errors.New("Empty Client Key Pem")
	}
	return ca.TLSCACerts.Client.KeyPem, nil
}
func (c *Config) CAClientCertPath(org string) (string, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return "", err
	}
	caName, err := c.getCAName(org)
	if err != nil {
		return "", err
	}
	if _, ok := config.CertificateAuthorities[strings.ToLower(caName)]; !ok {
		return "", errors.Errorf("CA Server Name '%s' not found", caName)
	}
	return substPathVars(config.CertificateAuthorities[strings.ToLower(caName)].TLSCACerts.Client.Certfile), nil
}
func (c *Config) CAClientCertPem(org string) (string, error) {
	config, err := c.NetworkConfig()
	if err != nil {
		return "", err
	}
	caName, err := c.getCAName(org)
	if err != nil {
		return "", err
	}
	if _, ok := config.CertificateAuthorities[strings.ToLower(caName)]; !ok {
		return "", errors.Errorf("CA Server Name '%s' not found", caName)
	}
	ca := config.CertificateAuthorities[strings.ToLower(caName)]
	if len(ca.TLSCACerts.Client.CertPem) == 0 {
		return "", errors.New("Empty Client Cert Pem")
	}
	return ca.TLSCACerts.Client.CertPem, nil
}
func (c *Config) TimeoutOrDefault(conn apiconfig.TimeoutType) time.Duration {
	var timeout time.Duration
	switch conn {
	case apiconfig.Endorser:
		timeout = c.configViper.GetDuration("client.peer.timeout.connection")
	case apiconfig.Query:
		timeout = c.configViper.GetDuration("client.peer.timeout.queryResponse")
	case apiconfig.Execute:
		timeout = c.configViper.GetDuration("client.peer.timeout.executeTxResponse")
	case apiconfig.DiscoveryGreylistExpiry:
		timeout = c.configViper.GetDuration("client.peer.timeout.discovery.greylistExpiry")
	case apiconfig.EventHub:
		timeout = c.configViper.GetDuration("client.eventService.timeout.connection")
	case apiconfig.EventReg:
		timeout = c.configViper.GetDuration("client.eventService.timeout.registrationResponse")
	case apiconfig.OrdererConnection:
		timeout = c.configViper.GetDuration("client.orderer.timeout.connection")
	case apiconfig.OrdererResponse:
		timeout = c.configViper.GetDuration("client.orderer.timeout.response")
	}
	if timeout == 0 {
		timeout = defaultTimeout
	}
	return timeout
}