WIP calls, remove SMS
This commit is contained in:
parent
d4767caf30
commit
f99159ee5b
16 changed files with 132 additions and 301 deletions
|
@ -47,7 +47,6 @@ const (
|
|||
DefaultVisitorMessageDailyLimit = 0
|
||||
DefaultVisitorEmailLimitBurst = 16
|
||||
DefaultVisitorEmailLimitReplenish = time.Hour
|
||||
DefaultVisitorSMSDailyLimit = 10
|
||||
DefaultVisitorCallDailyLimit = 10
|
||||
DefaultVisitorAccountCreationLimitBurst = 3
|
||||
DefaultVisitorAccountCreationLimitReplenish = 24 * time.Hour
|
||||
|
@ -130,7 +129,6 @@ type Config struct {
|
|||
VisitorMessageDailyLimit int
|
||||
VisitorEmailLimitBurst int
|
||||
VisitorEmailLimitReplenish time.Duration
|
||||
VisitorSMSDailyLimit int
|
||||
VisitorCallDailyLimit int
|
||||
VisitorAccountCreationLimitBurst int
|
||||
VisitorAccountCreationLimitReplenish time.Duration
|
||||
|
|
|
@ -106,14 +106,16 @@ var (
|
|||
errHTTPBadRequestNotAPaidUser = &errHTTP{40027, http.StatusBadRequest, "invalid request: not a paid user", "", nil}
|
||||
errHTTPBadRequestBillingRequestInvalid = &errHTTP{40028, http.StatusBadRequest, "invalid request: not a valid billing request", "", nil}
|
||||
errHTTPBadRequestBillingSubscriptionExists = &errHTTP{40029, http.StatusBadRequest, "invalid request: billing subscription already exists", "", nil}
|
||||
errHTTPBadRequestTwilioDisabled = &errHTTP{40030, http.StatusBadRequest, "invalid request: SMS and calling is disabled", "https://ntfy.sh/docs/publish/#sms", nil}
|
||||
errHTTPBadRequestPhoneNumberInvalid = &errHTTP{40031, http.StatusBadRequest, "invalid request: phone number invalid", "https://ntfy.sh/docs/publish/#sms", nil}
|
||||
errHTTPBadRequestTwilioDisabled = &errHTTP{40030, http.StatusBadRequest, "invalid request: Calling is disabled", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
||||
errHTTPBadRequestPhoneNumberInvalid = &errHTTP{40031, http.StatusBadRequest, "invalid request: phone number invalid", "https://ntfy.sh/docs/publish/#phone-calls", nil}
|
||||
errHTTPNotFound = &errHTTP{40401, http.StatusNotFound, "page not found", "", nil}
|
||||
errHTTPUnauthorized = &errHTTP{40101, http.StatusUnauthorized, "unauthorized", "https://ntfy.sh/docs/publish/#authentication", nil}
|
||||
errHTTPForbidden = &errHTTP{40301, http.StatusForbidden, "forbidden", "https://ntfy.sh/docs/publish/#authentication", nil}
|
||||
errHTTPConflictUserExists = &errHTTP{40901, http.StatusConflict, "conflict: user already exists", "", nil}
|
||||
errHTTPConflictTopicReserved = &errHTTP{40902, http.StatusConflict, "conflict: access control entry for topic or topic pattern already exists", "", nil}
|
||||
errHTTPConflictSubscriptionExists = &errHTTP{40903, http.StatusConflict, "conflict: topic subscription already exists", "", nil}
|
||||
errHTTPConflictPhoneNumberExists = &errHTTP{40904, http.StatusConflict, "conflict: phone number already exists", "", nil}
|
||||
errHTTPGonePhoneVerificationExpired = &errHTTP{41001, http.StatusGone, "phone number verification expired or does not exist", "", nil}
|
||||
errHTTPEntityTooLargeAttachment = &errHTTP{41301, http.StatusRequestEntityTooLarge, "attachment too large, or bandwidth limit reached", "https://ntfy.sh/docs/publish/#limitations", nil}
|
||||
errHTTPEntityTooLargeMatrixRequest = &errHTTP{41302, http.StatusRequestEntityTooLarge, "Matrix request is larger than the max allowed length", "", nil}
|
||||
errHTTPEntityTooLargeJSONBody = &errHTTP{41303, http.StatusRequestEntityTooLarge, "JSON body too large", "", nil}
|
||||
|
@ -126,8 +128,7 @@ var (
|
|||
errHTTPTooManyRequestsLimitReservations = &errHTTP{42907, http.StatusTooManyRequests, "limit reached: too many topic reservations for this user", "", nil}
|
||||
errHTTPTooManyRequestsLimitMessages = &errHTTP{42908, http.StatusTooManyRequests, "limit reached: daily message quota reached", "https://ntfy.sh/docs/publish/#limitations", nil}
|
||||
errHTTPTooManyRequestsLimitAuthFailure = &errHTTP{42909, http.StatusTooManyRequests, "limit reached: too many auth failures", "https://ntfy.sh/docs/publish/#limitations", nil} // FIXME document limit
|
||||
errHTTPTooManyRequestsLimitSMS = &errHTTP{42910, http.StatusTooManyRequests, "limit reached: daily SMS quota reached", "https://ntfy.sh/docs/publish/#limitations", nil}
|
||||
errHTTPTooManyRequestsLimitCalls = &errHTTP{42911, http.StatusTooManyRequests, "limit reached: daily phone call quota reached", "https://ntfy.sh/docs/publish/#limitations", nil}
|
||||
errHTTPTooManyRequestsLimitCalls = &errHTTP{42910, http.StatusTooManyRequests, "limit reached: daily phone call quota reached", "https://ntfy.sh/docs/publish/#limitations", nil}
|
||||
errHTTPInternalError = &errHTTP{50001, http.StatusInternalServerError, "internal server error", "", nil}
|
||||
errHTTPInternalErrorInvalidPath = &errHTTP{50002, http.StatusInternalServerError, "internal server error: invalid path", "", nil}
|
||||
errHTTPInternalErrorMissingBaseURL = &errHTTP{50003, http.StatusInternalServerError, "internal server error: base-url must be be configured for this feature", "https://ntfy.sh/docs/config/", nil}
|
||||
|
|
|
@ -534,7 +534,6 @@ func (s *Server) handleWebConfig(w http.ResponseWriter, _ *http.Request, _ *visi
|
|||
EnableLogin: s.config.EnableLogin,
|
||||
EnableSignup: s.config.EnableSignup,
|
||||
EnablePayments: s.config.StripeSecretKey != "",
|
||||
EnableSMS: s.config.TwilioAccount != "",
|
||||
EnableCalls: s.config.TwilioAccount != "",
|
||||
EnableReservations: s.config.EnableReservations,
|
||||
BillingContact: s.config.BillingContact,
|
||||
|
@ -676,7 +675,7 @@ func (s *Server) handlePublishInternal(r *http.Request, v *visitor) (*message, e
|
|||
return nil, err
|
||||
}
|
||||
m := newDefaultMessage(t.ID, "")
|
||||
cache, firebase, email, sms, call, unifiedpush, e := s.parsePublishParams(r, m)
|
||||
cache, firebase, email, call, unifiedpush, e := s.parsePublishParams(r, m)
|
||||
if e != nil {
|
||||
return nil, e.With(t)
|
||||
}
|
||||
|
@ -690,8 +689,6 @@ func (s *Server) handlePublishInternal(r *http.Request, v *visitor) (*message, e
|
|||
return nil, errHTTPTooManyRequestsLimitMessages.With(t)
|
||||
} else if email != "" && !vrate.EmailAllowed() {
|
||||
return nil, errHTTPTooManyRequestsLimitEmails.With(t)
|
||||
} else if sms != "" && !vrate.SMSAllowed() {
|
||||
return nil, errHTTPTooManyRequestsLimitSMS.With(t)
|
||||
} else if call != "" && !vrate.CallAllowed() {
|
||||
return nil, errHTTPTooManyRequestsLimitCalls.With(t)
|
||||
}
|
||||
|
@ -734,9 +731,6 @@ func (s *Server) handlePublishInternal(r *http.Request, v *visitor) (*message, e
|
|||
if s.smtpSender != nil && email != "" {
|
||||
go s.sendEmail(v, m, email)
|
||||
}
|
||||
if s.config.TwilioAccount != "" && sms != "" {
|
||||
go s.sendSMS(v, r, m, sms)
|
||||
}
|
||||
if s.config.TwilioAccount != "" && call != "" {
|
||||
go s.callPhone(v, r, m, call)
|
||||
}
|
||||
|
@ -849,7 +843,7 @@ func (s *Server) forwardPollRequest(v *visitor, m *message) {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, firebase bool, email, sms, call string, unifiedpush bool, err *errHTTP) {
|
||||
func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, firebase bool, email, call string, unifiedpush bool, err *errHTTP) {
|
||||
cache = readBoolParam(r, true, "x-cache", "cache")
|
||||
firebase = readBoolParam(r, true, "x-firebase", "firebase")
|
||||
m.Title = maybeDecodeHeader(readParam(r, "x-title", "title", "t"))
|
||||
|
@ -865,7 +859,7 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
|
|||
}
|
||||
if attach != "" {
|
||||
if !urlRegex.MatchString(attach) {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestAttachmentURLInvalid
|
||||
return false, false, "", "", false, errHTTPBadRequestAttachmentURLInvalid
|
||||
}
|
||||
m.Attachment.URL = attach
|
||||
if m.Attachment.Name == "" {
|
||||
|
@ -883,25 +877,19 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
|
|||
}
|
||||
if icon != "" {
|
||||
if !urlRegex.MatchString(icon) {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestIconURLInvalid
|
||||
return false, false, "", "", false, errHTTPBadRequestIconURLInvalid
|
||||
}
|
||||
m.Icon = icon
|
||||
}
|
||||
email = readParam(r, "x-email", "x-e-mail", "email", "e-mail", "mail", "e")
|
||||
if s.smtpSender == nil && email != "" {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestEmailDisabled
|
||||
}
|
||||
sms = readParam(r, "x-sms", "sms")
|
||||
if sms != "" && s.config.TwilioAccount == "" {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestTwilioDisabled
|
||||
} else if sms != "" && !phoneNumberRegex.MatchString(sms) {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestPhoneNumberInvalid
|
||||
return false, false, "", "", false, errHTTPBadRequestEmailDisabled
|
||||
}
|
||||
call = readParam(r, "x-call", "call")
|
||||
if call != "" && s.config.TwilioAccount == "" {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestTwilioDisabled
|
||||
return false, false, "", "", false, errHTTPBadRequestTwilioDisabled
|
||||
} else if call != "" && !phoneNumberRegex.MatchString(call) {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestPhoneNumberInvalid
|
||||
return false, false, "", "", false, errHTTPBadRequestPhoneNumberInvalid
|
||||
}
|
||||
messageStr := strings.ReplaceAll(readParam(r, "x-message", "message", "m"), "\\n", "\n")
|
||||
if messageStr != "" {
|
||||
|
@ -910,7 +898,7 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
|
|||
var e error
|
||||
m.Priority, e = util.ParsePriority(readParam(r, "x-priority", "priority", "prio", "p"))
|
||||
if e != nil {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestPriorityInvalid
|
||||
return false, false, "", "", false, errHTTPBadRequestPriorityInvalid
|
||||
}
|
||||
m.Tags = readCommaSeparatedParam(r, "x-tags", "tags", "tag", "ta")
|
||||
for i, t := range m.Tags {
|
||||
|
@ -919,18 +907,18 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
|
|||
delayStr := readParam(r, "x-delay", "delay", "x-at", "at", "x-in", "in")
|
||||
if delayStr != "" {
|
||||
if !cache {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestDelayNoCache
|
||||
return false, false, "", "", false, errHTTPBadRequestDelayNoCache
|
||||
}
|
||||
if email != "" {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestDelayNoEmail // we cannot store the email address (yet)
|
||||
return false, false, "", "", false, errHTTPBadRequestDelayNoEmail // we cannot store the email address (yet)
|
||||
}
|
||||
delay, err := util.ParseFutureTime(delayStr, time.Now())
|
||||
if err != nil {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestDelayCannotParse
|
||||
return false, false, "", "", false, errHTTPBadRequestDelayCannotParse
|
||||
} else if delay.Unix() < time.Now().Add(s.config.MinDelay).Unix() {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestDelayTooSmall
|
||||
return false, false, "", "", false, errHTTPBadRequestDelayTooSmall
|
||||
} else if delay.Unix() > time.Now().Add(s.config.MaxDelay).Unix() {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestDelayTooLarge
|
||||
return false, false, "", "", false, errHTTPBadRequestDelayTooLarge
|
||||
}
|
||||
m.Time = delay.Unix()
|
||||
}
|
||||
|
@ -938,7 +926,7 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
|
|||
if actionsStr != "" {
|
||||
m.Actions, e = parseActions(actionsStr)
|
||||
if e != nil {
|
||||
return false, false, "", "", "", false, errHTTPBadRequestActionsInvalid.Wrap(e.Error())
|
||||
return false, false, "", "", false, errHTTPBadRequestActionsInvalid.Wrap(e.Error())
|
||||
}
|
||||
}
|
||||
unifiedpush = readBoolParam(r, false, "x-unifiedpush", "unifiedpush", "up") // see GET too!
|
||||
|
@ -952,7 +940,7 @@ func (s *Server) parsePublishParams(r *http.Request, m *message) (cache bool, fi
|
|||
cache = false
|
||||
email = ""
|
||||
}
|
||||
return cache, firebase, email, sms, call, unifiedpush, nil
|
||||
return cache, firebase, email, call, unifiedpush, nil
|
||||
}
|
||||
|
||||
// handlePublishBody consumes the PUT/POST body and decides whether the body is an attachment or the message.
|
||||
|
|
|
@ -56,7 +56,6 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis
|
|||
Messages: limits.MessageLimit,
|
||||
MessagesExpiryDuration: int64(limits.MessageExpiryDuration.Seconds()),
|
||||
Emails: limits.EmailLimit,
|
||||
SMS: limits.SMSLimit,
|
||||
Calls: limits.CallLimit,
|
||||
Reservations: limits.ReservationsLimit,
|
||||
AttachmentTotalSize: limits.AttachmentTotalSizeLimit,
|
||||
|
@ -69,8 +68,6 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis
|
|||
MessagesRemaining: stats.MessagesRemaining,
|
||||
Emails: stats.Emails,
|
||||
EmailsRemaining: stats.EmailsRemaining,
|
||||
SMS: stats.SMS,
|
||||
SMSRemaining: stats.SMSRemaining,
|
||||
Calls: stats.Calls,
|
||||
CallsRemaining: stats.CallsRemaining,
|
||||
Reservations: stats.Reservations,
|
||||
|
@ -542,7 +539,7 @@ func (s *Server) handleAccountPhoneNumberAdd(w http.ResponseWriter, r *http.Requ
|
|||
// Check user is allowed to add phone numbers
|
||||
if u == nil || (u.IsUser() && u.Tier == nil) {
|
||||
return errHTTPUnauthorized
|
||||
} else if u.IsUser() && u.Tier.SMSLimit == 0 && u.Tier.CallLimit == 0 {
|
||||
} else if u.IsUser() && u.Tier.CallLimit == 0 {
|
||||
return errHTTPUnauthorized
|
||||
}
|
||||
// Actually add the unverified number, and send verification
|
||||
|
@ -553,6 +550,9 @@ func (s *Server) handleAccountPhoneNumberAdd(w http.ResponseWriter, r *http.Requ
|
|||
}).
|
||||
Debug("Adding phone number, and sending verification")
|
||||
if err := s.userManager.AddPhoneNumber(u.ID, req.Number); err != nil {
|
||||
if err == user.ErrPhoneNumberExists {
|
||||
return errHTTPConflictPhoneNumberExists
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err := s.verifyPhone(v, r, req.Number); err != nil {
|
||||
|
@ -570,10 +570,6 @@ func (s *Server) handleAccountPhoneNumberVerify(w http.ResponseWriter, r *http.R
|
|||
if !phoneNumberRegex.MatchString(req.Number) {
|
||||
return errHTTPBadRequestPhoneNumberInvalid
|
||||
}
|
||||
// Check user is allowed to add phone numbers
|
||||
if u == nil {
|
||||
return errHTTPUnauthorized
|
||||
}
|
||||
// Get phone numbers, and check if it's in the list
|
||||
phoneNumbers, err := s.userManager.PhoneNumbers(u.ID)
|
||||
if err != nil {
|
||||
|
@ -581,7 +577,7 @@ func (s *Server) handleAccountPhoneNumberVerify(w http.ResponseWriter, r *http.R
|
|||
}
|
||||
found := false
|
||||
for _, phoneNumber := range phoneNumbers {
|
||||
if phoneNumber.Number == req.Number && phoneNumber.Verified {
|
||||
if phoneNumber.Number == req.Number && !phoneNumber.Verified {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
|
|
@ -68,7 +68,6 @@ func (s *Server) handleBillingTiersGet(w http.ResponseWriter, _ *http.Request, _
|
|||
Messages: freeTier.MessageLimit,
|
||||
MessagesExpiryDuration: int64(freeTier.MessageExpiryDuration.Seconds()),
|
||||
Emails: freeTier.EmailLimit,
|
||||
SMS: freeTier.SMSLimit,
|
||||
Calls: freeTier.CallLimit,
|
||||
Reservations: freeTier.ReservationsLimit,
|
||||
AttachmentTotalSize: freeTier.AttachmentTotalSizeLimit,
|
||||
|
@ -98,7 +97,6 @@ func (s *Server) handleBillingTiersGet(w http.ResponseWriter, _ *http.Request, _
|
|||
Messages: tier.MessageLimit,
|
||||
MessagesExpiryDuration: int64(tier.MessageExpiryDuration.Seconds()),
|
||||
Emails: tier.EmailLimit,
|
||||
SMS: tier.SMSLimit,
|
||||
Calls: tier.CallLimit,
|
||||
Reservations: tier.ReservationLimit,
|
||||
AttachmentTotalSize: tier.AttachmentTotalSizeLimit,
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
twilioMessageEndpoint = "Messages.json"
|
||||
twilioMessageFooterFormat = "This message was sent by %s via %s"
|
||||
twilioCallEndpoint = "Calls.json"
|
||||
twilioCallFormat = `
|
||||
|
@ -32,15 +31,6 @@ const (
|
|||
</Response>`
|
||||
)
|
||||
|
||||
func (s *Server) sendSMS(v *visitor, r *http.Request, m *message, to string) {
|
||||
body := fmt.Sprintf("%s\n\n--\n%s", m.Message, s.messageFooter(v.User(), m))
|
||||
data := url.Values{}
|
||||
data.Set("From", s.config.TwilioFromNumber)
|
||||
data.Set("To", to)
|
||||
data.Set("Body", body)
|
||||
s.twilioMessagingRequest(v, r, m, metricSMSSentSuccess, metricSMSSentFailure, twilioMessageEndpoint, to, body, data)
|
||||
}
|
||||
|
||||
func (s *Server) callPhone(v *visitor, r *http.Request, m *message, to string) {
|
||||
body := fmt.Sprintf(twilioCallFormat, xmlEscapeText(m.Topic), xmlEscapeText(m.Message), xmlEscapeText(s.messageFooter(v.User(), m)))
|
||||
data := url.Values{}
|
||||
|
@ -85,25 +75,38 @@ func (s *Server) checkVerifyPhone(v *visitor, r *http.Request, phoneNumber, code
|
|||
data := url.Values{}
|
||||
data.Set("To", phoneNumber)
|
||||
data.Set("Code", code)
|
||||
requestURL := fmt.Sprintf("%s/v2/Services/%s/VerificationCheck", s.config.TwilioVerifyBaseURL, s.config.TwilioAccount)
|
||||
requestURL := fmt.Sprintf("%s/v2/Services/%s/VerificationCheck", s.config.TwilioVerifyBaseURL, s.config.TwilioVerifyService)
|
||||
req, err := http.NewRequest(http.MethodPost, requestURL, strings.NewReader(data.Encode()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Authorization", util.BasicAuth(s.config.TwilioAccount, s.config.TwilioAuthToken))
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
log.Fields(httpContext(req)).Field("http_body", data.Encode()).Info("Twilio call")
|
||||
ev := logvr(v, r).
|
||||
Tag(tagTwilio).
|
||||
Field("twilio_to", phoneNumber)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
if ev.IsTrace() {
|
||||
response, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ev.Field("twilio_response", string(response))
|
||||
}
|
||||
ev.Warn("Twilio phone verification failed with status code %d", resp.StatusCode)
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return errHTTPGonePhoneVerificationExpired
|
||||
}
|
||||
return errHTTPInternalError
|
||||
}
|
||||
response, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ev := logvr(v, r).Tag(tagTwilio)
|
||||
if ev.IsTrace() {
|
||||
ev.Field("twilio_response", string(response)).Trace("Received successful Twilio phone verification response")
|
||||
} else if ev.IsDebug() {
|
||||
|
|
|
@ -362,7 +362,6 @@ type apiConfigResponse struct {
|
|||
EnableLogin bool `json:"enable_login"`
|
||||
EnableSignup bool `json:"enable_signup"`
|
||||
EnablePayments bool `json:"enable_payments"`
|
||||
EnableSMS bool `json:"enable_sms"`
|
||||
EnableCalls bool `json:"enable_calls"`
|
||||
EnableReservations bool `json:"enable_reservations"`
|
||||
BillingContact string `json:"billing_contact"`
|
||||
|
|
|
@ -56,7 +56,6 @@ type visitor struct {
|
|||
requestLimiter *rate.Limiter // Rate limiter for (almost) all requests (including messages)
|
||||
messagesLimiter *util.FixedLimiter // Rate limiter for messages
|
||||
emailsLimiter *util.RateLimiter // Rate limiter for emails
|
||||
smsLimiter *util.FixedLimiter // Rate limiter for SMS
|
||||
callsLimiter *util.FixedLimiter // Rate limiter for calls
|
||||
subscriptionLimiter *util.FixedLimiter // Fixed limiter for active subscriptions (ongoing connections)
|
||||
bandwidthLimiter *util.RateLimiter // Limiter for attachment bandwidth downloads
|
||||
|
@ -81,7 +80,6 @@ type visitorLimits struct {
|
|||
EmailLimit int64
|
||||
EmailLimitBurst int
|
||||
EmailLimitReplenish rate.Limit
|
||||
SMSLimit int64
|
||||
CallLimit int64
|
||||
ReservationsLimit int64
|
||||
AttachmentTotalSizeLimit int64
|
||||
|
@ -95,8 +93,6 @@ type visitorStats struct {
|
|||
MessagesRemaining int64
|
||||
Emails int64
|
||||
EmailsRemaining int64
|
||||
SMS int64
|
||||
SMSRemaining int64
|
||||
Calls int64
|
||||
CallsRemaining int64
|
||||
Reservations int64
|
||||
|
@ -115,11 +111,10 @@ const (
|
|||
)
|
||||
|
||||
func newVisitor(conf *Config, messageCache *messageCache, userManager *user.Manager, ip netip.Addr, user *user.User) *visitor {
|
||||
var messages, emails, sms, calls int64
|
||||
var messages, emails, calls int64
|
||||
if user != nil {
|
||||
messages = user.Stats.Messages
|
||||
emails = user.Stats.Emails
|
||||
sms = user.Stats.SMS
|
||||
calls = user.Stats.Calls
|
||||
}
|
||||
v := &visitor{
|
||||
|
@ -134,13 +129,12 @@ func newVisitor(conf *Config, messageCache *messageCache, userManager *user.Mana
|
|||
requestLimiter: nil, // Set in resetLimiters
|
||||
messagesLimiter: nil, // Set in resetLimiters, may be nil
|
||||
emailsLimiter: nil, // Set in resetLimiters
|
||||
smsLimiter: nil, // Set in resetLimiters, may be nil
|
||||
callsLimiter: nil, // Set in resetLimiters, may be nil
|
||||
bandwidthLimiter: nil, // Set in resetLimiters
|
||||
accountLimiter: nil, // Set in resetLimiters, may be nil
|
||||
authLimiter: nil, // Set in resetLimiters, may be nil
|
||||
}
|
||||
v.resetLimitersNoLock(messages, emails, sms, calls, false)
|
||||
v.resetLimitersNoLock(messages, emails, calls, false)
|
||||
return v
|
||||
}
|
||||
|
||||
|
@ -168,9 +162,6 @@ func (v *visitor) contextNoLock() log.Context {
|
|||
fields["visitor_emails_remaining"] = info.Stats.EmailsRemaining
|
||||
}
|
||||
if v.config.TwilioAccount != "" {
|
||||
fields["visitor_sms"] = info.Stats.SMS
|
||||
fields["visitor_sms_limit"] = info.Limits.SMSLimit
|
||||
fields["visitor_sms_remaining"] = info.Stats.SMSRemaining
|
||||
fields["visitor_calls"] = info.Stats.Calls
|
||||
fields["visitor_calls_limit"] = info.Limits.CallLimit
|
||||
fields["visitor_calls_remaining"] = info.Stats.CallsRemaining
|
||||
|
@ -238,12 +229,6 @@ func (v *visitor) EmailAllowed() bool {
|
|||
return v.emailsLimiter.Allow()
|
||||
}
|
||||
|
||||
func (v *visitor) SMSAllowed() bool {
|
||||
v.mu.RLock() // limiters could be replaced!
|
||||
defer v.mu.RUnlock()
|
||||
return v.smsLimiter.Allow()
|
||||
}
|
||||
|
||||
func (v *visitor) CallAllowed() bool {
|
||||
v.mu.RLock() // limiters could be replaced!
|
||||
defer v.mu.RUnlock()
|
||||
|
@ -330,7 +315,6 @@ func (v *visitor) Stats() *user.Stats {
|
|||
return &user.Stats{
|
||||
Messages: v.messagesLimiter.Value(),
|
||||
Emails: v.emailsLimiter.Value(),
|
||||
SMS: v.smsLimiter.Value(),
|
||||
Calls: v.callsLimiter.Value(),
|
||||
}
|
||||
}
|
||||
|
@ -340,7 +324,6 @@ func (v *visitor) ResetStats() {
|
|||
defer v.mu.RUnlock()
|
||||
v.emailsLimiter.Reset()
|
||||
v.messagesLimiter.Reset()
|
||||
v.smsLimiter.Reset()
|
||||
v.callsLimiter.Reset()
|
||||
}
|
||||
|
||||
|
@ -372,11 +355,11 @@ func (v *visitor) SetUser(u *user.User) {
|
|||
shouldResetLimiters := v.user.TierID() != u.TierID() // TierID works with nil receiver
|
||||
v.user = u // u may be nil!
|
||||
if shouldResetLimiters {
|
||||
var messages, emails, sms, calls int64
|
||||
var messages, emails, calls int64
|
||||
if u != nil {
|
||||
messages, emails, sms, calls = u.Stats.Messages, u.Stats.Emails, u.Stats.SMS, u.Stats.Calls
|
||||
messages, emails, calls = u.Stats.Messages, u.Stats.Emails, u.Stats.Calls
|
||||
}
|
||||
v.resetLimitersNoLock(messages, emails, sms, calls, true)
|
||||
v.resetLimitersNoLock(messages, emails, calls, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,12 +374,11 @@ func (v *visitor) MaybeUserID() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (v *visitor) resetLimitersNoLock(messages, emails, sms, calls int64, enqueueUpdate bool) {
|
||||
func (v *visitor) resetLimitersNoLock(messages, emails, calls int64, enqueueUpdate bool) {
|
||||
limits := v.limitsNoLock()
|
||||
v.requestLimiter = rate.NewLimiter(limits.RequestLimitReplenish, limits.RequestLimitBurst)
|
||||
v.messagesLimiter = util.NewFixedLimiterWithValue(limits.MessageLimit, messages)
|
||||
v.emailsLimiter = util.NewRateLimiterWithValue(limits.EmailLimitReplenish, limits.EmailLimitBurst, emails)
|
||||
v.smsLimiter = util.NewFixedLimiterWithValue(limits.SMSLimit, sms)
|
||||
v.callsLimiter = util.NewFixedLimiterWithValue(limits.CallLimit, calls)
|
||||
v.bandwidthLimiter = util.NewBytesLimiter(int(limits.AttachmentBandwidthLimit), oneDay)
|
||||
if v.user == nil {
|
||||
|
@ -410,7 +392,6 @@ func (v *visitor) resetLimitersNoLock(messages, emails, sms, calls int64, enqueu
|
|||
go v.userManager.EnqueueUserStats(v.user.ID, &user.Stats{
|
||||
Messages: messages,
|
||||
Emails: emails,
|
||||
SMS: sms,
|
||||
Calls: calls,
|
||||
})
|
||||
}
|
||||
|
@ -440,7 +421,6 @@ func tierBasedVisitorLimits(conf *Config, tier *user.Tier) *visitorLimits {
|
|||
EmailLimit: tier.EmailLimit,
|
||||
EmailLimitBurst: util.MinMax(int(float64(tier.EmailLimit)*visitorEmailLimitBurstRate), conf.VisitorEmailLimitBurst, visitorEmailLimitBurstMax),
|
||||
EmailLimitReplenish: dailyLimitToRate(tier.EmailLimit),
|
||||
SMSLimit: tier.SMSLimit,
|
||||
CallLimit: tier.CallLimit,
|
||||
ReservationsLimit: tier.ReservationLimit,
|
||||
AttachmentTotalSizeLimit: tier.AttachmentTotalSizeLimit,
|
||||
|
@ -464,7 +444,6 @@ func configBasedVisitorLimits(conf *Config) *visitorLimits {
|
|||
EmailLimit: replenishDurationToDailyLimit(conf.VisitorEmailLimitReplenish), // Approximation!
|
||||
EmailLimitBurst: conf.VisitorEmailLimitBurst,
|
||||
EmailLimitReplenish: rate.Every(conf.VisitorEmailLimitReplenish),
|
||||
SMSLimit: int64(conf.VisitorSMSDailyLimit),
|
||||
CallLimit: int64(conf.VisitorCallDailyLimit),
|
||||
ReservationsLimit: visitorDefaultReservationsLimit,
|
||||
AttachmentTotalSizeLimit: conf.VisitorAttachmentTotalSizeLimit,
|
||||
|
@ -511,7 +490,6 @@ func (v *visitor) Info() (*visitorInfo, error) {
|
|||
func (v *visitor) infoLightNoLock() *visitorInfo {
|
||||
messages := v.messagesLimiter.Value()
|
||||
emails := v.emailsLimiter.Value()
|
||||
sms := v.smsLimiter.Value()
|
||||
calls := v.callsLimiter.Value()
|
||||
limits := v.limitsNoLock()
|
||||
stats := &visitorStats{
|
||||
|
@ -519,8 +497,6 @@ func (v *visitor) infoLightNoLock() *visitorInfo {
|
|||
MessagesRemaining: zeroIfNegative(limits.MessageLimit - messages),
|
||||
Emails: emails,
|
||||
EmailsRemaining: zeroIfNegative(limits.EmailLimit - emails),
|
||||
SMS: sms,
|
||||
SMSRemaining: zeroIfNegative(limits.SMSLimit - sms),
|
||||
Calls: calls,
|
||||
CallsRemaining: zeroIfNegative(limits.CallLimit - calls),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue