github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/srpc/serverutil/perUserMethodLimiter.go (about)

     1  package serverutil
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
     7  )
     8  
     9  func newPerUserMethodLimiter(
    10  	perUserMethodLimitsInput map[string]uint) *PerUserMethodLimiter {
    11  	perUserMethodLimits := make(map[string]uint, len(perUserMethodLimitsInput))
    12  	for method, limit := range perUserMethodLimitsInput {
    13  		perUserMethodLimits[method] = limit
    14  	}
    15  	return &PerUserMethodLimiter{
    16  		perUserMethodCounts: make(map[userMethodType]uint,
    17  			len(perUserMethodLimits)),
    18  		perUserMethodLimits: perUserMethodLimits,
    19  	}
    20  }
    21  
    22  func (limiter *PerUserMethodLimiter) blockMethod(methodName string,
    23  	authInfo *srpc.AuthInformation) (func(), error) {
    24  	if authInfo.HaveMethodAccess {
    25  		return nil, nil
    26  	}
    27  	limiter.mutex.Lock()
    28  	defer limiter.mutex.Unlock()
    29  	if limit := limiter.perUserMethodLimits[methodName]; limit < 1 {
    30  		return nil, nil
    31  	} else {
    32  		userMethod := userMethodType{
    33  			method:   methodName,
    34  			username: authInfo.Username,
    35  		}
    36  		if count := limiter.perUserMethodCounts[userMethod]; count >= limit {
    37  			return nil, fmt.Errorf("%s reached limit of %d calls for %s",
    38  				authInfo.Username, limit, methodName)
    39  		} else {
    40  			limiter.perUserMethodCounts[userMethod] = count + 1
    41  			return func() {
    42  				limiter.mutex.Lock()
    43  				defer limiter.mutex.Unlock()
    44  				if count := limiter.perUserMethodCounts[userMethod]; count < 1 {
    45  					panic(fmt.Sprintf("%s has no %s calls to release",
    46  						authInfo.Username, methodName))
    47  				} else {
    48  					if count -= 1; count < 1 {
    49  						delete(limiter.perUserMethodCounts, userMethod)
    50  					} else {
    51  						limiter.perUserMethodCounts[userMethod] = count
    52  					}
    53  				}
    54  			}, nil
    55  		}
    56  	}
    57  }