// NewWithID creates a new client connected to server available at // addr, identifying using the custom id provided. func NewWithID(addr string, id string, opts ...Option) (*Client, error) { var connectionOpts []connection.Option for _, opt := range opts { connectionOpts = append(connectionOpts, connection.Option(opt)) } conn, err := connection.New(addr, connectionOpts...) if err != nil { return nil, err } client := &Client{ id: id, conn: conn, resources: make(map[string]*resourceImpl), newResource: make(chan resourceAction), releaseResource: make(chan resourceAction), goRoutineHalted: make(chan bool), } go client.run() return client, nil }
// NewIntermediate creates a server connected to the lower level server. func NewIntermediate(ctx context.Context, id string, addr string, leader election.Election, opts ...connection.Option) (*Server, error) { var ( conn *connection.Connection updater updater err error ) isRootServer := addr == "" // Set up some configuration for intermediate server: establish a connection // to a lower-level server (e.g. the root server) and assign the updater function. if !isRootServer { if conn, err = connection.New(addr, opts...); err != nil { return nil, err } updater = func(server *Server, retryNumber int) (time.Duration, int) { return server.performRequests(ctx, retryNumber) } } server := &Server{ ID: id, Election: leader, isConfigured: make(chan bool), resources: make(map[string]*Resource), becameMasterAt: time.Unix(0, 0), conn: conn, updater: updater, quit: make(chan bool), } const ( namespace = "doorman" subsystem = "server" ) labelNames := []string{"resource"} server.descs.has = prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, "has"), "All capacity assigned to clients for a resource.", labelNames, nil, ) server.descs.wants = prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, "wants"), "All capacity requested by clients for a resource.", labelNames, nil, ) server.descs.subclients = prometheus.NewDesc( prometheus.BuildFQName(namespace, subsystem, "subclients"), "Number of clients requesting this resource.", labelNames, nil, ) // For an intermediate server load the default config for "*" // resource. As for root server, this config will be loaded // from some external source.. if !isRootServer { if err := server.LoadConfig(ctx, &pb.ResourceRepository{ Resources: []*pb.ResourceTemplate{ proto.Clone(defaultResourceTemplate).(*pb.ResourceTemplate), }, }, map[string]*time.Time{}); err != nil { return nil, err } } go server.run() return server, nil }