fixed up use of context to stop loops by using a select with case <-ctx.Done()
This commit is contained in:
+15
-12
@@ -101,19 +101,22 @@ func AmDeliverSubscription(ctx context.Context, comm *database.Community, conf *
|
|||||||
|
|
||||||
// The delivery loop; build each message and send it. Note that sending a message puts the Message structure on
|
// The delivery loop; build each message and send it. Note that sending a message puts the Message structure on
|
||||||
// the sender goroutine channel, so we have to create a new Message each time, unlike what we did in Venice.
|
// the sender goroutine channel, so we have to create a new Message each time, unlike what we did in Venice.
|
||||||
|
SendLoop:
|
||||||
for i := range recipUids {
|
for i := range recipUids {
|
||||||
err = ctx.Err()
|
select {
|
||||||
if err != nil {
|
case <-ctx.Done():
|
||||||
log.Errorf("AmDeliverSubscription: aborted on send loop iter %d with %v", i+1, err)
|
log.Errorf("AmDeliverSubscription: aborted on send loop iter %d with %v", i+1, ctx.Err())
|
||||||
}
|
break SendLoop
|
||||||
if ci, err := database.AmGetContactInfoForUser(ctx, recipUids[i]); err == nil {
|
default:
|
||||||
msg := AmNewEmailMessage(poster.Uid, ipaddr)
|
if ci, err := database.AmGetContactInfoForUser(ctx, recipUids[i]); err == nil {
|
||||||
msg.SetSubject(subjectSink.GetSubject())
|
msg := AmNewEmailMessage(poster.Uid, ipaddr)
|
||||||
msg.SetText(sendText)
|
msg.SetSubject(subjectSink.GetSubject())
|
||||||
msg.AddTo(*ci.Email, ci.FullName(false))
|
msg.SetText(sendText)
|
||||||
msg.Send()
|
msg.AddTo(*ci.Email, ci.FullName(false))
|
||||||
} else {
|
msg.Send()
|
||||||
log.Warnf("AmDeliverSubscription skipped uid %d because no contact info retrieved (%v)", recipUids[i], err)
|
} else {
|
||||||
|
log.Warnf("AmDeliverSubscription skipped uid %d because no contact info retrieved (%v)", recipUids[i], err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+146
-145
@@ -801,168 +801,169 @@ func (ht *htmlCheckerImpl) finishParen() error {
|
|||||||
func (ht *htmlCheckerImpl) parse(str string) error {
|
func (ht *htmlCheckerImpl) parse(str string) error {
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(str) {
|
for i < len(str) {
|
||||||
err := ht.ctx.Err()
|
select {
|
||||||
if err != nil {
|
case <-ht.ctx.Done():
|
||||||
return err
|
return ht.ctx.Err()
|
||||||
}
|
default:
|
||||||
ch := str[i]
|
ch := str[i]
|
||||||
switch ht.state {
|
switch ht.state {
|
||||||
case stateWhitespace:
|
case stateWhitespace:
|
||||||
switch ch {
|
switch ch {
|
||||||
case ' ', '\t': // append space and tab verbatim
|
case ' ', '\t': // append space and tab verbatim
|
||||||
ht.tempBuffer.WriteByte(ch)
|
ht.tempBuffer.WriteByte(ch)
|
||||||
i++
|
i++
|
||||||
case '\r', '\n': // flush and go to Newline state
|
case '\r', '\n': // flush and go to Newline state
|
||||||
ht.doFlushWhitespace()
|
ht.doFlushWhitespace()
|
||||||
ht.state = stateNewline
|
ht.state = stateNewline
|
||||||
ht.tempBuffer.WriteByte(ch)
|
ht.tempBuffer.WriteByte(ch)
|
||||||
i++
|
i++
|
||||||
case '<':
|
case '<':
|
||||||
ht.doFlushWhitespace()
|
ht.doFlushWhitespace()
|
||||||
if ht.config.Angles {
|
if ht.config.Angles {
|
||||||
ht.state = stateLeftAngle
|
ht.state = stateLeftAngle
|
||||||
} else {
|
} else {
|
||||||
// process < as ordinary character
|
// process < as ordinary character
|
||||||
|
ht.state = stateChars
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
case '(':
|
||||||
|
ht.doFlushWhitespace()
|
||||||
|
if ht.config.Parens {
|
||||||
|
ht.state = stateParen
|
||||||
|
} else {
|
||||||
|
// process ( as ordinary character)
|
||||||
|
ht.state = stateChars
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
case '\\': // backslash processing is tricky - go to Chars state to handle it
|
||||||
|
ht.doFlushWhitespace()
|
||||||
|
ht.state = stateChars
|
||||||
|
default:
|
||||||
|
ht.doFlushWhitespace()
|
||||||
ht.state = stateChars
|
ht.state = stateChars
|
||||||
ht.tempBuffer.WriteByte(ch)
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
i++
|
||||||
}
|
}
|
||||||
i++
|
case stateChars:
|
||||||
case '(':
|
switch ch {
|
||||||
ht.doFlushWhitespace()
|
case ' ', '\t': // go to Whitespace state
|
||||||
if ht.config.Parens {
|
|
||||||
ht.state = stateParen
|
|
||||||
} else {
|
|
||||||
// process ( as ordinary character)
|
|
||||||
ht.state = stateChars
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
case '\\': // backslash processing is tricky - go to Chars state to handle it
|
|
||||||
ht.doFlushWhitespace()
|
|
||||||
ht.state = stateChars
|
|
||||||
default:
|
|
||||||
ht.doFlushWhitespace()
|
|
||||||
ht.state = stateChars
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
case stateChars:
|
|
||||||
switch ch {
|
|
||||||
case ' ', '\t': // go to Whitespace state
|
|
||||||
_, err := ht.doFlushString()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ht.state = stateWhitespace
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
i++
|
|
||||||
case '\r', '\n': // go to Newline state
|
|
||||||
_, err := ht.doFlushString()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ht.state = stateNewline
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
i++
|
|
||||||
case '<': // may be a start of tag
|
|
||||||
if ht.config.Angles {
|
|
||||||
_, err := ht.doFlushString()
|
_, err := ht.doFlushString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ht.state = stateLeftAngle
|
ht.state = stateWhitespace
|
||||||
} else {
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
case '\\':
|
|
||||||
if i < (len(str) - 1) {
|
|
||||||
i++
|
|
||||||
ch = str[i]
|
|
||||||
if (ch == '(' && ht.config.Parens) || (ch == '<' && ht.config.Angles) {
|
|
||||||
// append the escaped character, omitting the backslash
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
i++
|
|
||||||
} else {
|
|
||||||
// append the backslash and hit the new character
|
|
||||||
ht.tempBuffer.WriteByte('\\')
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// just append the backslash normally
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
ht.tempBuffer.WriteByte(ch)
|
||||||
i++
|
i++
|
||||||
}
|
case '\r', '\n': // go to Newline state
|
||||||
default: // just append the next character
|
_, err := ht.doFlushString()
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
case stateLeftAngle:
|
|
||||||
switch ch {
|
|
||||||
case ' ', '\t', '\r', '\n': // output <, go to Whitespace state
|
|
||||||
ht.emitRune('<', ht.outputFilters, true)
|
|
||||||
ht.state = stateWhitespace
|
|
||||||
case '<': // output < and stay in this state
|
|
||||||
ht.emitRune('<', ht.outputFilters, true)
|
|
||||||
i++
|
|
||||||
default: // begin processing tag
|
|
||||||
ht.state = stateTag
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
case stateTag:
|
|
||||||
switch ch {
|
|
||||||
case '>': // finish the tag - this changes the state, and possibly calls parse() recursively
|
|
||||||
err := ht.finishTag()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
case '\'', '"': // go into "quote string" state inside the tag
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
ht.state = stateTagQuote
|
|
||||||
ht.quoteChar = ch
|
|
||||||
i++
|
|
||||||
default: // just append the character
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
case stateParen:
|
|
||||||
switch ch {
|
|
||||||
case '(': // nest parentheses one level deeper
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
ht.parenLevel++
|
|
||||||
i++
|
|
||||||
case ')':
|
|
||||||
if ht.parenLevel == 0 {
|
|
||||||
err := ht.finishParen() // finish paren, changing state and recursively parsing if necessary
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
ht.state = stateNewline
|
||||||
// nest parentheses one LESS level deeper
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
ht.tempBuffer.WriteByte(ch)
|
||||||
ht.parenLevel--
|
i++
|
||||||
|
case '<': // may be a start of tag
|
||||||
|
if ht.config.Angles {
|
||||||
|
_, err := ht.doFlushString()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ht.state = stateLeftAngle
|
||||||
|
} else {
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
case '\\':
|
||||||
|
if i < (len(str) - 1) {
|
||||||
|
i++
|
||||||
|
ch = str[i]
|
||||||
|
if (ch == '(' && ht.config.Parens) || (ch == '<' && ht.config.Angles) {
|
||||||
|
// append the escaped character, omitting the backslash
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
// append the backslash and hit the new character
|
||||||
|
ht.tempBuffer.WriteByte('\\')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// just append the backslash normally
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
default: // just append the next character
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
case stateLeftAngle:
|
||||||
|
switch ch {
|
||||||
|
case ' ', '\t', '\r', '\n': // output <, go to Whitespace state
|
||||||
|
ht.emitRune('<', ht.outputFilters, true)
|
||||||
|
ht.state = stateWhitespace
|
||||||
|
case '<': // output < and stay in this state
|
||||||
|
ht.emitRune('<', ht.outputFilters, true)
|
||||||
|
i++
|
||||||
|
default: // begin processing tag
|
||||||
|
ht.state = stateTag
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
case stateTag:
|
||||||
|
switch ch {
|
||||||
|
case '>': // finish the tag - this changes the state, and possibly calls parse() recursively
|
||||||
|
err := ht.finishTag()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
case '\'', '"': // go into "quote string" state inside the tag
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
ht.state = stateTagQuote
|
||||||
|
ht.quoteChar = ch
|
||||||
|
i++
|
||||||
|
default: // just append the character
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
case stateParen:
|
||||||
|
switch ch {
|
||||||
|
case '(': // nest parentheses one level deeper
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
ht.parenLevel++
|
||||||
|
i++
|
||||||
|
case ')':
|
||||||
|
if ht.parenLevel == 0 {
|
||||||
|
err := ht.finishParen() // finish paren, changing state and recursively parsing if necessary
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// nest parentheses one LESS level deeper
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
ht.parenLevel--
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
default:
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
case stateTagQuote:
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
if ch == ht.quoteChar {
|
||||||
|
ht.state = stateTag
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
|
case stateNewline:
|
||||||
|
if ch == '\r' || ch == '\n' {
|
||||||
|
ht.tempBuffer.WriteByte(ch)
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
ht.doFlushNewlines()
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
ht.tempBuffer.WriteByte(ch)
|
log.Fatalf("invalid parser state: %d", ht.state)
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
case stateTagQuote:
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
if ch == ht.quoteChar {
|
|
||||||
ht.state = stateTag
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
case stateNewline:
|
|
||||||
if ch == '\r' || ch == '\n' {
|
|
||||||
ht.tempBuffer.WriteByte(ch)
|
|
||||||
i++
|
|
||||||
} else {
|
|
||||||
ht.doFlushNewlines()
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
log.Fatalf("invalid parser state: %d", ht.state)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user