<commit_before>// Copyright (C) 2014 <NAME> <<EMAIL>>
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package events

import (
	"database/sql"
	"time"

	"github.com/xconstruct/stark/core"
	"github.com/xconstruct/stark/proto"
)

var Module = core.Module{
	Name:        "events",
	Version:     "1.0",
	NewInstance: newInstance,
}

func init() {
	core.RegisterModule(Module)
}

func newInstance(ctx *core.Context) (core.ModuleInstance, error) {
	return NewService(ctx)
}

type Service struct {
	DB    Database
	ctx   *core.Context
	proto *proto.Client
}

func NewService(ctx *core.Context) (*Service, error) {
	s := &Service{
		DB:    &sqlDatabase{ctx.Database.Driver(), ctx.Database.DB},
		ctx:   ctx,
		proto: proto.NewClient("events", ctx.Proto),
	}
	return s, nil
}

func (s *Service) Enable() error {
	if err := s.DB.Setup(); err != nil {
		return err
	}
	if err := s.proto.Subscribe("event/new", "", s.handleEventNew); err != nil {
		return err
	}
	if err := s.proto.Subscribe("event/last", "", s.handleEventLast); err != nil {
		return err
	}
	if err := s.proto.Subscribe("location/fence", "", s.handleLocationFence); err != nil {
		return err
	}
	return nil
}

func (s *Service) Disable() error { return nil }

var MessageEventNotFound = proto.Message{
	Action: "event/notfound",
	Text:   "No event found.",
}

func fixEvent(e *Event) {
	if e.Timestamp.IsZero() {
		e.Timestamp = time.Now()
	}
	if e.Subject == "i" || e.Subject == "I" {
		e.Subject = "user"
	}
}

func (s *Service) handleEventNew(msg proto.Message) {
	var e Event
	if err := msg.DecodePayload(&e); err != nil {
		s.ctx.Log.Warnln("[events] received bad payload:", err)
		s.publish(msg.Reply(proto.BadRequest(err)))
		return
	}
	fixEvent(&e)

	s.ctx.Log.Infoln("[events] new event:", e)

	if err := s.DB.StoreEvent(e); err != nil {
		s.ctx.Log.Errorln("[vents] could not store event:", err)
		s.publish(msg.Reply(proto.InternalError(err)))
		return
	}

	reply := proto.Message{Action: "event/created"}
	if err := reply.EncodePayload(e); err != nil {
		s.ctx.Log.Errorln("[events] could not encode reply:", err)
		s.publish(msg.Reply(proto.InternalError(err)))
		return
	}
	reply.Text = "New event: " + e.String()

	s.publish(msg.Reply(reply))
}

func (s *Service) handleEventLast(msg proto.Message) {
	var filter Event
	if err := msg.DecodePayload(&filter); err != nil {
		s.ctx.Log.Warnln("[events] received bad payload:", err)
		s.publish(msg.Reply(proto.BadRequest(err)))
		return
	}
	fixEvent(&filter)

	s.ctx.Log.Infoln("[events] get last by filter:", filter)
	last, err := s.DB.GetLastEvent(filter)
	if err != nil {
		if err == sql.ErrNoRows {
			s.publish(msg.Reply(MessageEventNotFound))
			return
		}
		s.ctx.Log.Errorln("[events] could not get events:", err)
		s.publish(msg.Reply(proto.InternalError(err)))
		return
	}
	s.ctx.Log.Infoln("[events] found", last)

	reply := proto.Message{Action: "event/found"}
	if err := reply.EncodePayload(last); err != nil {
		s.ctx.Log.Errorln("[events] could not encode reply:", err)
		s.publish(msg.Reply(proto.InternalError(err)))
		return
	}
	reply.Text = last.String()

	s.publish(msg.Reply(reply))
}

func (s *Service) publish(msg proto.Message) {
	if err := s.proto.Publish(msg); err != nil {
		s.ctx.Log.Errorln(err)
	}
}
<commit_msg>Events: Fix handling natural text.<commit_after>// Copyright (C) 2014 <NAME> <<EMAIL>>
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package events

import (
	"database/sql"
	"time"

	"github.com/xconstruct/stark/core"
	"github.com/xconstruct/stark/proto"
)

var Module = core.Module{
	Name:        "events",
	Version:     "1.0",
	NewInstance: newInstance,
}

func init() {
	core.RegisterModule(Module)
}

func newInstance(ctx *core.Context) (core.ModuleInstance, error) {
	return NewService(ctx)
}

type Service struct {
	DB    Database
	ctx   *core.Context
	proto *proto.Client
}

func NewService(ctx *core.Context) (*Service, error) {
	s := &Service{
		DB:    &sqlDatabase{ctx.Database.Driver(), ctx.Database.DB},
		ctx:   ctx,
		proto: proto.NewClient("events", ctx.Proto),
	}
	return s, nil
}

func (s *Service) Enable() error {
	if err := s.DB.Setup(); err != nil {
		return err
	}
	if err := s.proto.Subscribe("event/new", "", s.handleEventNew); err != nil {
		return err
	}
	if err := s.proto.Subscribe("event/last", "", s.handleEventLast); err != nil {
		return err
	}
	if err := s.proto.Subscribe("location/fence", "", s.handleLocationFence); err != nil {
		return err
	}
	return nil
}

func (s *Service) Disable() error { return nil }

var MessageEventNotFound = proto.Message{
	Action: "event/notfound",
	Text:   "No event found.",
}

func fixEvent(e *Event) {
	if e.Timestamp.IsZero() {
		e.Timestamp = time.Now()
	}
	if e.Subject == "i" || e.Subject == "I" {
		e.Subject = "user"
	}
}

func (s *Service) handleEventNew(msg proto.Message) {
	var e Event
	if err := msg.DecodePayload(&e); err != nil {
		s.ctx.Log.Warnln("[events] received bad payload:", err)
		s.publish(msg.Reply(proto.BadRequest(err)))
		return
	}
	fixEvent(&e)
	if e.Text == "" {
		e.Text = msg.Text
	}

	s.ctx.Log.Infoln("[events] new event:", e)

	if err := s.DB.StoreEvent(e); err != nil {
		s.ctx.Log.Errorln("[vents] could not store event:", err)
		s.publish(msg.Reply(proto.InternalError(err)))
		return
	}

	reply := proto.Message{Action: "event/created"}
	if err := reply.EncodePayload(e); err != nil {
		s.ctx.Log.Errorln("[events] could not encode reply:", err)
		s.publish(msg.Reply(proto.InternalError(err)))
		return
	}
	reply.Text = "New event: " + e.String()

	s.publish(msg.Reply(reply))
}

func (s *Service) handleEventLast(msg proto.Message) {
	var filter Event
	if err := msg.DecodePayload(&filter); err != nil {
		s.ctx.Log.Warnln("[events] received bad payload:", err)
		s.publish(msg.Reply(proto.BadRequest(err)))
		return
	}
	fixEvent(&filter)

	s.ctx.Log.Infoln("[events] get last by filter:", filter)
	last, err := s.DB.GetLastEvent(filter)
	if err != nil {
		if err == sql.ErrNoRows {
			s.publish(msg.Reply(MessageEventNotFound))
			return
		}
		s.ctx.Log.Errorln("[events] could not get events:", err)
		s.publish(msg.Reply(proto.InternalError(err)))
		return
	}
	s.ctx.Log.Infoln("[events] found", last)

	reply := proto.Message{Action: "event/found"}
	if err := reply.EncodePayload(last); err != nil {
		s.ctx.Log.Errorln("[events] could not encode reply:", err)
		s.publish(msg.Reply(proto.InternalError(err)))
		return
	}
	reply.Text = last.String()

	s.publish(msg.Reply(reply))
}

func (s *Service) publish(msg proto.Message) {
	if err := s.proto.Publish(msg); err != nil {
		s.ctx.Log.Errorln(err)
	}
}

{'fraction_non_alphanumeric': 0.17061894108873973, 'fraction_numerical': 0.0017897091722595079, 'mean_word_length': 3.8383838383838382, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3190189', 'n_tokens_mistral': 2524, 'n_tokens_neox': 2444, 'n_words': 576}