add rss & crawl & webhook
This commit is contained in:
@@ -124,10 +124,9 @@ func (c *aggrChannel) Send(ctx context.Context, receiver Receiver, group *route.
|
||||
if receiver.Email != "" && c.email != nil {
|
||||
return c.send(ctx, receiver, group, c.email, "email")
|
||||
}
|
||||
// if receiver.Webhook != nil && c.webhook != nil {
|
||||
// TODO: temporarily disable webhook to reduce copyright risks.
|
||||
// return c.send(ctx, receiver, group, c.webhook, "webhook")
|
||||
// }
|
||||
if receiver.Webhook != nil && c.webhook != nil {
|
||||
return c.send(ctx, receiver, group, c.webhook, "webhook")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -134,53 +134,53 @@ func (e *email) buildEmail(receiver Receiver, group *route.FeedGroup) (*gomail.M
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "build email body HTML")
|
||||
}
|
||||
m.SetBody("text/html", string(body))
|
||||
m.SetBody("text/html", body)
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (e *email) buildBodyHTML(group *route.FeedGroup) ([]byte, error) {
|
||||
func (e *email) buildBodyHTML(group *route.FeedGroup) (string, error) {
|
||||
bodyBuf := buffer.Get()
|
||||
defer buffer.Put(bodyBuf)
|
||||
|
||||
// Write HTML header.
|
||||
if err := e.writeHTMLHeader(bodyBuf); err != nil {
|
||||
return nil, errors.Wrap(err, "write HTML header")
|
||||
return "", errors.Wrap(err, "write HTML header")
|
||||
}
|
||||
|
||||
// Write summary.
|
||||
if err := e.writeSummary(bodyBuf, group.Summary); err != nil {
|
||||
return nil, errors.Wrap(err, "write summary")
|
||||
return "", errors.Wrap(err, "write summary")
|
||||
}
|
||||
|
||||
// Write each feed content.
|
||||
if _, err := bodyBuf.WriteString(`
|
||||
<div style="margin-top:20px; padding-top:15px; border-top:1px solid #f1f3f4;">
|
||||
<p style="font-size:32px; font-weight:500; margin:0 0 10px 0;">Feeds</p>`); err != nil {
|
||||
return nil, errors.Wrap(err, "write feeds header")
|
||||
return "", errors.Wrap(err, "write feeds header")
|
||||
}
|
||||
for i, feed := range group.Feeds {
|
||||
if err := e.writeFeedContent(bodyBuf, feed); err != nil {
|
||||
return nil, errors.Wrap(err, "write feed content")
|
||||
return "", errors.Wrap(err, "write feed content")
|
||||
}
|
||||
|
||||
// Add separator (except the last feed).
|
||||
if i < len(group.Feeds)-1 {
|
||||
if err := e.writeSeparator(bodyBuf); err != nil {
|
||||
return nil, errors.Wrap(err, "write separator")
|
||||
return "", errors.Wrap(err, "write separator")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write disclaimer and HTML footer.
|
||||
if err := e.writeDisclaimer(bodyBuf); err != nil {
|
||||
return nil, errors.Wrap(err, "write disclaimer")
|
||||
return "", errors.Wrap(err, "write disclaimer")
|
||||
}
|
||||
if err := e.writeHTMLFooter(bodyBuf); err != nil {
|
||||
return nil, errors.Wrap(err, "write HTML footer")
|
||||
return "", errors.Wrap(err, "write HTML footer")
|
||||
}
|
||||
|
||||
return bodyBuf.Bytes(), nil
|
||||
return bodyBuf.String(), nil
|
||||
}
|
||||
|
||||
func (e *email) writeHTMLHeader(buf *buffer.Bytes) error {
|
||||
|
||||
@@ -41,9 +41,10 @@ func (r *WebhookReceiver) Validate() error {
|
||||
}
|
||||
|
||||
type webhookBody struct {
|
||||
Group string `json:"group"`
|
||||
Labels model.Labels `json:"labels"`
|
||||
Feeds []*route.Feed `json:"feeds"`
|
||||
Group string `json:"group"`
|
||||
Labels model.Labels `json:"labels"`
|
||||
Summary string `json:"summary"`
|
||||
Feeds []*route.Feed `json:"feeds"`
|
||||
}
|
||||
|
||||
func newWebhook() sender {
|
||||
@@ -59,9 +60,10 @@ type webhook struct {
|
||||
func (w *webhook) Send(ctx context.Context, receiver Receiver, group *route.FeedGroup) error {
|
||||
// Prepare request.
|
||||
body := &webhookBody{
|
||||
Group: group.Name,
|
||||
Labels: group.Labels,
|
||||
Feeds: group.Feeds,
|
||||
Group: group.Name,
|
||||
Labels: group.Labels,
|
||||
Summary: group.Summary,
|
||||
Feeds: group.Feeds,
|
||||
}
|
||||
b := runtimeutil.Must1(json.Marshal(body))
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, receiver.Webhook.URL, bytes.NewReader(b))
|
||||
|
||||
@@ -86,9 +86,9 @@ func (c *Config) From(app *config.App) *Config {
|
||||
if app.Notify.Receivers[i].Email != "" {
|
||||
c.Receivers[i].Email = app.Notify.Receivers[i].Email
|
||||
}
|
||||
// if app.Notify.Receivers[i].Webhook != nil {
|
||||
// c.Receivers[i].Webhook = &channel.WebhookReceiver{URL: app.Notify.Receivers[i].Webhook.URL}
|
||||
// }
|
||||
if app.Notify.Receivers[i].Webhook != nil {
|
||||
c.Receivers[i].Webhook = &channel.WebhookReceiver{URL: app.Notify.Receivers[i].Webhook.URL}
|
||||
}
|
||||
}
|
||||
|
||||
c.Channels = channel.Config{}
|
||||
@@ -438,8 +438,8 @@ func (n *notifier) send(ctx context.Context, work sendWork) error {
|
||||
return channel.Send(ctx, work.receiver.Receiver, work.group)
|
||||
}
|
||||
|
||||
var nlogKey = func(group *route.FeedGroup, receiver Receiver) string {
|
||||
return fmt.Sprintf("notifier.group.%s.receiver.%s.%d", group.Name, receiver.Name, group.Time.Unix())
|
||||
var nlogKey = func(group *route.FeedGroup, receiver Receiver) []byte {
|
||||
return fmt.Appendf(nil, "notifier.group.%s.receiver.%s.%d", group.Name, receiver.Name, group.Time.Unix())
|
||||
}
|
||||
|
||||
func (n *notifier) isSent(ctx context.Context, group *route.FeedGroup, receiver Receiver) bool {
|
||||
@@ -457,7 +457,7 @@ func (n *notifier) isSent(ctx context.Context, group *route.FeedGroup, receiver
|
||||
}
|
||||
|
||||
func (n *notifier) markSent(ctx context.Context, group *route.FeedGroup, receiver Receiver) error {
|
||||
return n.Dependencies().KVStorage.Set(ctx, nlogKey(group, receiver), timeutil.Format(time.Now()), timeutil.Day)
|
||||
return n.Dependencies().KVStorage.Set(ctx, nlogKey(group, receiver), []byte(timeutil.Format(time.Now())), timeutil.Day)
|
||||
}
|
||||
|
||||
type sendWork struct {
|
||||
|
||||
@@ -72,56 +72,25 @@ func (s SubRoutes) Match(feed *block.FeedVO) *SubRoute {
|
||||
type SubRoute struct {
|
||||
Route
|
||||
Matchers []string
|
||||
matchers []matcher
|
||||
matchers model.LabelFilters
|
||||
}
|
||||
|
||||
func (r *SubRoute) Match(feed *block.FeedVO) *SubRoute {
|
||||
// Match sub routes.
|
||||
for _, subRoute := range r.SubRoutes {
|
||||
if matched := subRoute.Match(feed); matched != nil {
|
||||
return matched
|
||||
}
|
||||
}
|
||||
for _, m := range r.matchers {
|
||||
fv := feed.Labels.Get(m.key)
|
||||
switch m.equal {
|
||||
case true:
|
||||
if fv != m.value {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
if fv == m.value {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Match self.
|
||||
if !r.matchers.Match(feed.Labels) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
type matcher struct {
|
||||
key string
|
||||
value string
|
||||
equal bool
|
||||
}
|
||||
|
||||
var (
|
||||
matcherEqual = "="
|
||||
matcherNotEqual = "!="
|
||||
parseMatcher = func(filter string) (matcher, error) {
|
||||
eq := false
|
||||
parts := strings.Split(filter, matcherNotEqual)
|
||||
if len(parts) != 2 {
|
||||
parts = strings.Split(filter, matcherEqual)
|
||||
eq = true
|
||||
}
|
||||
if len(parts) != 2 {
|
||||
return matcher{}, errors.New("invalid matcher")
|
||||
}
|
||||
|
||||
return matcher{key: parts[0], value: parts[1], equal: eq}, nil
|
||||
}
|
||||
)
|
||||
|
||||
func (r *SubRoute) Validate() error {
|
||||
if len(r.GroupBy) == 0 {
|
||||
r.GroupBy = []string{model.LabelSource}
|
||||
@@ -129,17 +98,16 @@ func (r *SubRoute) Validate() error {
|
||||
if r.CompressByRelatedThreshold == nil {
|
||||
r.CompressByRelatedThreshold = ptr.To(float32(0.85))
|
||||
}
|
||||
|
||||
if len(r.Matchers) == 0 {
|
||||
return errors.New("matchers is required")
|
||||
}
|
||||
r.matchers = make([]matcher, len(r.Matchers))
|
||||
for i, matcher := range r.Matchers {
|
||||
m, err := parseMatcher(matcher)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid matcher")
|
||||
}
|
||||
r.matchers[i] = m
|
||||
matchers, err := model.NewLabelFilters(r.Matchers)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid matchers")
|
||||
}
|
||||
r.matchers = matchers
|
||||
|
||||
for _, subRoute := range r.SubRoutes {
|
||||
if err := subRoute.Validate(); err != nil {
|
||||
return errors.Wrap(err, "invalid sub_route")
|
||||
@@ -151,7 +119,7 @@ func (r *SubRoute) Validate() error {
|
||||
|
||||
func (c *Config) Validate() error {
|
||||
if len(c.GroupBy) == 0 {
|
||||
c.GroupBy = []string{model.LabelSource}
|
||||
c.GroupBy = []string{model.LabelType}
|
||||
}
|
||||
if c.CompressByRelatedThreshold == nil {
|
||||
c.CompressByRelatedThreshold = ptr.To(float32(0.85))
|
||||
@@ -179,8 +147,8 @@ type FeedGroup struct {
|
||||
Name string
|
||||
Time time.Time
|
||||
Labels model.Labels
|
||||
Feeds []*Feed
|
||||
Summary string
|
||||
Feeds []*Feed
|
||||
}
|
||||
|
||||
func (g *FeedGroup) ID() string {
|
||||
|
||||
Reference in New Issue
Block a user