예제 #1
0
func (s *Service) HandleQuery(msg sarif.Message) {
	var f Fact
	if err := msg.DecodePayload(&f); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	f, err := s.InterpretLiterals(f)
	if err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	var facts []*Fact
	if err := s.DB.Where(f).Limit(100).Find(&facts).Error; err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	if facts, err = s.AddLabelFacts(facts); err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	s.Reply(msg, sarif.CreateMessage("concepts/result", &resultPayload{
		ToJsonLd(facts),
		facts,
	}))
}
예제 #2
0
func (s *Service) HandleQueryExternal(msg sarif.Message) {
	var f Fact
	if err := msg.DecodePayload(&f); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	facts := []*Fact{&f}
	FillVariables(facts)

	var r sparql.ResourceResponse
	q := sparql.DBPedia.Query()
	q = BuildQuery(q, facts)
	if err := q.Exec(&r); err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	result := ApplyBindings(facts, r.Results.Bindings, sparql.CommonPrefixes)
	s.Reply(msg, sarif.CreateMessage("concepts/result", &resultPayload{
		ToJsonLd(result),
		result,
	}))

	for _, f := range result {
		if err := s.DB.FirstOrCreate(&f, &f).Error; err != nil {
			s.Log("err", "[reasoner] error updating external fact: "+err.Error())
		}
	}
}
예제 #3
0
func (s *Service) handleEventLast(msg sarif.Message) {
	filter := make(map[string]interface{})
	if err := msg.DecodePayload(&filter); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	s.Log("debug", "get last by filter:", filter)
	var events []Event
	err := s.Store.Scan("events", store.Scan{
		Reverse: true,
		Only:    "values",
		Filter:  filter,
		Limit:   1,
	}, &events)
	if err != nil {
		s.ReplyInternalError(msg, err)
	}
	if len(events) == 0 {
		s.Reply(msg, MessageEventNotFound)
		return
	}
	s.Log("debug", "last - found", events)

	reply := sarif.Message{Action: "event/found"}
	if err := reply.EncodePayload(events[0]); err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	reply.Text = events[0].String()

	s.Reply(msg, reply)
}
예제 #4
0
func (s *Service) handleEventRecord(msg sarif.Message) {
	var p recordPayload
	if err := msg.DecodePayload(&p); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	if p.Action == "" {
		s.ReplyBadRequest(msg, errors.New("No action specified"))
		return
	}

	var cfg Config
	s.cfg.Get(&cfg)
	if cfg.RecordedActions == nil {
		cfg.RecordedActions = make(map[string]bool)
	}
	if enabled := cfg.RecordedActions[p.Action]; !enabled {
		cfg.RecordedActions[p.Action] = true
		s.cfg.Set(cfg)
		s.Subscribe(p.Action, "", s.handleEventNew)
	}

	s.Log("debug", "recording action:", p.Action)
	s.Reply(msg, sarif.CreateMessage("event/recording", p))
}
예제 #5
0
func (s *Service) handleEventList(msg sarif.Message) {
	var filter map[string]interface{}
	if err := msg.DecodePayload(&filter); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	if filter == nil {
		filter = make(map[string]interface{})
	}
	reverse := false
	if len(filter) == 0 {
		filter["time >="] = time.Now().Add(-24 * time.Hour)
		reverse = true
	}

	s.Log("debug", "list by filter:", filter)
	var events []Event
	err := s.Store.Scan("events", store.Scan{
		Only:    "values",
		Filter:  filter,
		Reverse: reverse,
	}, &events)
	if err != nil {
		s.ReplyInternalError(msg, err)
	}
	s.Log("debug", "list - found", len(events))

	s.Reply(msg, sarif.CreateMessage("events/listed", &aggPayload{
		Type:   "list",
		Filter: filter,
		Events: events,
		Value:  float64(len(events)),
	}))
}
예제 #6
0
func (s *Service) handlePut(msg sarif.Message) {
	collection, key := parseAction("store/put/", msg.Action)
	if collection == "" {
		s.ReplyBadRequest(msg, errors.New("No collection specified."))
		return
	}

	if len(msg.Payload.Raw) == 0 && msg.Text != "" {
		v, _ := json.Marshal(msg.Text)
		msg.Payload.Raw = json.RawMessage(v)
	}
	var p interface{}
	if err := msg.DecodePayload(&p); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	// TODO: maybe a JSON payload consistency check
	doc, err := s.Store.Put(&Document{
		Collection: collection,
		Key:        key,
		Value:      msg.Payload.Raw,
	})
	if err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	doc.Value = nil
	reply := sarif.CreateMessage("store/updated/"+doc.Collection+"/"+doc.Key, doc)
	s.Reply(msg, reply)

	pub := sarif.CreateMessage("store/updated/"+doc.Collection+"/"+doc.Key, doc)
	s.Publish(pub)
}
예제 #7
0
func (s *Service) handleScan(msg sarif.Message) {
	collection, prefix := parseAction("store/scan/", msg.Action)
	if collection == "" {
		s.ReplyBadRequest(msg, errors.New("No collection specified."))
		return
	}

	var p scanMessage
	if err := msg.DecodePayload(&p); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	if p.Start == "" && p.End == "" {
		if p.Prefix == "" {
			p.Prefix = prefix
		}
	}

	got, err := s.doScan(collection, p)
	if err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	s.Reply(msg, sarif.CreateMessage("store/scanned/"+collection, got))
}
예제 #8
0
func (s *Service) handleLuaLoad(msg sarif.Message) {
	gen := false
	name := strings.TrimPrefix(strings.TrimPrefix(msg.Action, "lua/load"), "/")
	if name == "" {
		name, gen = sarif.GenerateId(), true
	}
	if _, ok := s.Machines[name]; ok {
		s.destroyMachine(name)
	}

	m, err := s.createMachine(name)
	if err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	var ctp ContentPayload
	if err := msg.DecodePayload(&ctp); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	text := msg.Text
	if ctp.Content.Url != "" {
		ct, err := content.Get(ctp.Content)
		if err != nil {
			s.ReplyBadRequest(msg, err)
		}
		text = string(ct.Data)
	}

	var gp interface{}
	msg.DecodePayload(&gp)
	out, err, _ := m.Do(text, gp)
	if err != nil {
		s.ReplyBadRequest(msg, err)
		s.destroyMachine(name)
		return
	}

	if !gen {
		f, err := os.Create(s.cfg.ScriptDir + "/" + name + ".lua")
		if err == nil {
			_, err = f.Write([]byte(text))
			defer f.Close()
		}
		if err != nil {
			s.ReplyInternalError(msg, err)
			s.destroyMachine(name)
			return
		}
	}

	s.Reply(msg, sarif.CreateMessage("lua/loaded", &MsgMachineStatus{
		name,
		"up",
		out,
	}))
}
예제 #9
0
func (s *Scheduler) handle(msg sarif.Message) {
	var t ScheduleMessage
	if err := msg.DecodePayload(&t); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	now := time.Now()
	t.Task.Time = now
	if t.Time != "" {
		t.Task.Time = futureTime(util.ParseTime(t.Time, now))
	}
	if t.RandomAfter != "" && t.RandomBefore != "" {
		after := futureTime(util.ParseTime(t.RandomAfter, t.Task.Time))
		before := futureTime(util.ParseTime(t.RandomBefore, t.Task.Time))
		if before.Before(after) {
			after, before = before, after
		}
		maxDur := int64(before.Sub(after))
		ranDur := time.Duration(rand.Int63n(maxDur))
		t.Task.Time = after.Add(ranDur)
	}
	if t.Duration != "" {
		dur, err := util.ParseDuration(t.Duration)
		if err != nil {
			s.ReplyBadRequest(msg, err)
			return
		}
		t.Task.Time = t.Task.Time.Add(dur)
	}
	if t.Task.Reply.Action == "" {
		text := msg.Text
		if text == "" {
			text = "Reminder from " + time.Now().Format(time.RFC3339) + " finished."
		}
		t.Task.Reply = sarif.Message{
			Action:      "schedule/finished",
			Destination: msg.Source,
			Text:        text,
		}
	}
	if t.Task.Reply.CorrId == "" {
		t.Reply.CorrId = msg.Id
	}
	s.Log("info", "new task:", t)

	if _, err := s.Store.Put(t.Task.Key(), &t.Task); err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	go s.recalculateTimer()
	s.Reply(msg, sarif.CreateMessage("schedule/created", t.Task))
}
예제 #10
0
func (s *Service) handleServingRecord(msg sarif.Message) {
	var sv Serving
	if err := msg.DecodePayload(&sv); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	size, name := splitSizeName(msg.Text)
	if sv.Size == 0 {
		sv.Size = size
	}
	if sv.Name == "" {
		sv.Name = name
	}
	if sv.Product == nil {
		ps, err := s.findProduct(sv.Name)
		if err != nil {
			s.ReplyBadRequest(msg, err)
			return
		}

		if len(ps) > 1 {
			pList := ""
			for _, p := range ps {
				pList += "\n- " + p.Name
			}
			s.ReplyBadRequest(msg, fmt.Errorf("%d products named %s found.%s", len(ps), sv.Name, pList))
			return
		}
		if len(ps) == 1 {
			sv.Product = &ps[0]
		}
	}
	if sv.AmountWeight <= 0 {
		sv.AmountWeight = Weight(sv.Size) * sv.Product.ServingWeight
	}
	if sv.AmountVolume <= 0 {
		sv.AmountVolume = Volume(sv.Size) * sv.Product.ServingVolume
	}
	if sv.AmountWeight <= 0 && sv.AmountVolume <= 0 {
		s.ReplyBadRequest(msg, errors.New("No serving amount specified."))
		return
	}
	if sv.Time.IsZero() {
		sv.Time = time.Now()
	}

	if err := s.DB.Save(&sv).Error; err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	s.Reply(msg, sarif.CreateMessage("meal/serving/recorded", &sv))
}
예제 #11
0
func (s *MessageSchemaStore) AddMessage(msg *sarif.Message) {
	schema := &MessageSchema{
		Action: msg.Action,
		Fields: make(map[string]string),
	}
	p := make(map[string]interface{})
	msg.DecodePayload(&p)
	for v, _ := range p {
		schema.Fields[v] = "text"
	}

	s.Add(schema)
}
예제 #12
0
func (s *Service) handleBatch(msg sarif.Message) {
	cmds := make([]BatchCommand, 0)
	if err := msg.DecodePayload(&cmds); err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	results := make([]interface{}, len(cmds))
	for i, cmd := range cmds {
		collection, key := parseAction("", cmd.Key)
		switch cmd.Type {
		case "put":
			doc, err := s.Store.Put(&Document{
				Collection: collection,
				Key:        key,
				Value:      []byte(cmd.Value),
			})
			if err != nil {
				s.ReplyInternalError(msg, err)
				return
			}
			results[i] = doc
		case "get":
			doc, err := s.Store.Get(collection, key)
			if err != nil {
				s.ReplyInternalError(msg, err)
				return
			}
			results[i] = doc
		case "del":
			if err := s.Store.Del(collection, key); err != nil {
				s.ReplyInternalError(msg, err)
				return
			}
			results[i] = true
		case "scan":
			var p scanMessage
			if err := json.Unmarshal(cmd.Value, &p); err != nil {
				s.ReplyInternalError(msg, err)
				return
			}
			got, err := s.doScan(collection, p)
			if err != nil {
				s.ReplyInternalError(msg, err)
				return
			}
			results[i] = got
		}
	}

	s.Reply(msg, sarif.CreateMessage("store/batched/", results))
}
예제 #13
0
func (s *Service) handleLocationUpdate(msg sarif.Message) {
	loc := Location{}
	if err := msg.DecodePayload(&loc); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	if loc.Time.IsZero() {
		loc.Time = time.Now()
	}
	loc.Geohash = EncodeGeohash(loc.Latitude, loc.Longitude, 12)
	s.Log("debug", "store update", loc)

	var last []Location
	err := s.Store.Scan("locations", store.Scan{
		Reverse: true,
		Only:    "values",
		Limit:   1,
	}, &last)
	if err != nil {
		s.Log("err/internal", "retrieve last err: "+err.Error())
	}
	if len(last) > 0 {
		loc.Distance = HaversineDistance(last[0], loc)
		loc.Speed = loc.Distance / loc.Time.Sub(last[0].Time).Seconds()
	}

	if _, err := s.Store.Put(loc.Key(), &loc); err != nil {
		s.ReplyInternalError(msg, err)
	}

	if changed := s.Clusters.Advance(loc); changed {
		c := s.Clusters.Current()
		status := "enter"
		if c.Status != ConfirmedCluster {
			status = "leave"
			c = s.Clusters.LastCompleted()
			s.Clusters.ClearCompleted()
		}

		// TODO: make optional
		if place, err := ReverseGeocode(c.Location); err == nil {
			c.Address = place.Pretty()
		}

		s.Publish(sarif.CreateMessage("location/cluster/"+status, c))
	}

	if len(last) > 0 {
		s.checkGeofences(last[0], loc)
	}
}
예제 #14
0
파일: util.go 프로젝트: sarifsystems/sarif
func messageToTable(L *lua.LState, msg sarif.Message) lua.LValue {
	t := L.NewTable()
	tableSetString(t, "sarif", msg.Version)
	tableSetString(t, "id", msg.Id)
	tableSetString(t, "action", msg.Action)
	tableSetString(t, "src", msg.Source)
	tableSetString(t, "dest", msg.Destination)
	tableSetString(t, "corr", msg.CorrId)
	tableSetString(t, "text", msg.Text)

	p := make(map[string]interface{})
	msg.DecodePayload(&p)
	t.RawSetH(lua.LString("p"), luareflect.ToLua(L, p))
	return t
}
예제 #15
0
func (s *Service) handleNaturalParse(msg sarif.Message) {
	ctx := &natural.Context{}
	msg.DecodePayload(ctx)
	if ctx.Text == "" {
		ctx.Text = msg.Text
	}

	res, err := s.parser.Parse(ctx)
	if err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	s.Reply(msg, sarif.CreateMessage("natural/parsed", res))
}
예제 #16
0
func (cv *Conversation) SendToClient(msg sarif.Message) {
	// Save conversation.
	cv.LastTime = time.Now()
	cv.LastMessage = msg

	// Analyze message for possible user actions
	cv.LastMessageAction = Actionable{}
	msg.DecodePayload(&cv.LastMessageAction)

	msg = cv.service.AnnotateReply(msg)

	// Forward response to client.
	msg.Id = sarif.GenerateId()
	msg.Destination = cv.Device
	cv.service.Publish(msg)
}
예제 #17
0
func (s *Service) handleNaturalReinforce(msg sarif.Message) {
	var p msgLearn
	if err := msg.DecodePayload(&p); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	if p.Sentence == "" || p.Action == "" {
		s.ReplyBadRequest(msg, errors.New("No sentence or action given."))
		return
	}

	s.Log("info", "reinforcing '"+p.Sentence+"' with "+p.Action)
	s.parser.ReinforceSentence(p.Sentence, p.Action)

	parsed, _ := s.parser.Parse(&natural.Context{Text: p.Sentence})
	s.Reply(msg, sarif.CreateMessage("natural/learned/meaning", &msgLearn{p.Sentence, parsed.Intents[0].Message.Action}))
}
예제 #18
0
func (s *Service) handleAuthRequest(msg sarif.Message) {
	var ci sarif.ClientInfo
	msg.DecodePayload(&ci)
	if ci.Auth == "" {
		return
	}

	authed := false
	auths := strings.Split(ci.Auth, ",")
	for _, auth := range auths {
		if s.Config.Tokens[auth] || s.SessionTokens[auth].After(time.Now()) {
			authed = true
		}
	}
	if !authed {
		return
	}

	s.Reply(msg, sarif.CreateMessage("proto/allow", nil))
}
예제 #19
0
func (s *Server) handleJson(msg sarif.Message) {
	req, err := parseActionAsURL(msg.Action)
	if err != nil {
		s.Client.ReplyBadRequest(msg, err)
		return
	}
	if err := msg.DecodePayload(req); err != nil {
		s.Client.ReplyBadRequest(msg, err)
		return
	}

	hr, err := http.NewRequest(strings.ToUpper(req.Method), req.Url, nil)
	if err != nil {
		s.Client.ReplyBadRequest(msg, err)
		return
	}

	client := &http.Client{}
	resp, err := client.Do(hr)
	if err != nil {
		s.Client.ReplyBadRequest(msg, err)
		return
	}
	defer resp.Body.Close()

	var r interface{}
	if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
		s.Client.ReplyBadRequest(msg, err)
		return
	}

	x, err := extract(r, strings.Split(req.Extract, "/"))
	if err != nil {
		s.Client.ReplyBadRequest(msg, err)
		return
	}
	s.Client.Reply(msg, sarif.CreateMessage("json/done", &jsonResponse{
		Request: req,
		Result:  x,
	}))
}
예제 #20
0
func (s *Service) handleNaturalLearn(msg sarif.Message) {
	var p msgLearn
	if err := msg.DecodePayload(&p); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	p.Sentence = strings.TrimSpace(p.Sentence)
	if p.Sentence == "" {
		return
	}
	p.Action = strings.TrimLeft(p.Action, "./")

	if err := s.regular.Learn(p.Sentence, p.Action); err != nil {
		s.ReplyBadRequest(msg, err)
	}
	s.Log("info", "associating '"+p.Sentence+"' with "+p.Action)
	s.Reply(msg, sarif.CreateMessage("natural/learned/meaning", p))

	s.Cfg.Rules = s.regular.Rules()
	s.Config.Set(&s.Cfg)
}
예제 #21
0
func (s *Service) HandleStore(msg sarif.Message) {
	var f Fact
	if err := msg.DecodePayload(&f); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	f, err := s.InterpretLiterals(f)
	if err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	db := s.DB.Where(Fact{Subject: f.Subject, Predicate: f.Predicate})
	db = s.DB.Assign(f)
	if err := db.FirstOrCreate(&f).Error; err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	s.Reply(msg, sarif.CreateMessage("concepts/stored", &f))
}
예제 #22
0
func (s *Service) handleTag(msg sarif.Message) {
	var p tagPayload
	p.Artist = msg.Text
	if err := msg.DecodePayload(&p); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	api := NewApi(s.cfg.ApiKey)
	tags, err := api.ArtistGetTopTags(p.Artist)
	if err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	p.Artist = tags.TopTags.Attr.Artist
	p.Genre, p.BroadGenre = FindGenre(tags.TopTags.Tags)
	for _, t := range tags.TopTags.Tags {
		p.Tags = append(p.Tags, t.Name)
	}
	s.Reply(msg, sarif.CreateMessage("lastfm/tagged", p))
}
예제 #23
0
func (s *Service) handleLuaDo(msg sarif.Message) {
	machine := strings.TrimLeft(strings.TrimPrefix(msg.Action, "lua/do"), "/")
	if machine == "" {
		machine = "default"
	}
	m, err := s.getOrCreateMachine(machine)
	if err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	var gp interface{}
	msg.DecodePayload(&gp)
	out, err, p := m.Do(msg.Text, gp)
	if err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	reply := sarif.CreateMessage("lua/done", p)
	reply.Text = out
	s.Reply(msg, reply)
}
예제 #24
0
func (s *Service) handleEventNew(msg sarif.Message) {
	isTargeted := msg.IsAction("event/new")

	var e Event
	e.Text = msg.Text
	e.Time = time.Now()
	e.Value = 1
	if s, v, ok := parseDataFromAction(msg.Action, "event/new"); ok {
		e.Action, e.Value = s, v
	}
	if err := msg.DecodePayload(&e); err != nil && isTargeted {
		s.ReplyBadRequest(msg, err)
		return
	}

	if err := msg.DecodePayload(&e.Meta); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	if e.Time.IsZero() {
		e.Time = time.Now()
	}

	if _, err := s.Store.Put(e.Key(), &e); err != nil {
		s.Log("err/internal", "could not store finished task: "+err.Error())
		return
	}

	if isTargeted {
		reply := sarif.Message{Action: "event/created"}
		if err := reply.EncodePayload(e); err != nil {
			s.ReplyInternalError(msg, err)
			return
		}
		reply.Text = "New event: " + e.String()
		s.Reply(msg, reply)
	}
}
예제 #25
0
func (s *Service) handleNaturalParse(msg sarif.Message) {
	ctx := &natural.Context{}
	msg.DecodePayload(ctx)
	if ctx.Text == "" {
		ctx.Text = msg.Text
	}

	res, err := s.parser.Parse(ctx)
	if err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	// Before we would try querying the generic store,
	// let's try to guess an objects location
	if len(res.Intents) > 0 && strings.HasPrefix(res.Intents[0].Message.Action, "store/scan/") {
		it := res.Intents[0]
		object := strings.TrimPrefix(it.Message.Action, "store/scan/")
		if ok := s.ObjectsTried[object]; !ok {
			s.ObjectsTried[object] = true
			singular := strings.Trim(object, "s")

			select {
			case <-s.Discover(object + "/list"):
				it.Message.Action = object + "/list"
				s.Cfg.ObjectLocations[object] = it.Message.Action
				s.Config.Set(&s.Cfg)
			case <-s.Discover(singular + "/list"):
				it.Message.Action = singular + "/list"
				s.Cfg.ObjectLocations[object] = it.Message.Action
				s.Config.Set(&s.Cfg)
			case <-time.After(time.Second):
			}
		}
	}

	s.Reply(msg, sarif.CreateMessage("natural/parsed", res))
}
예제 #26
0
func (s *Service) handleProductNew(msg sarif.Message) {
	var p Product
	if err := msg.DecodePayload(&p); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	if p.Name == "" {
		s.ReplyBadRequest(msg, errors.New("Please specify a product name."))
		return
	}
	if p.ServingWeight == 0 && p.ServingVolume == 0 {
		s.ReplyBadRequest(msg, errors.New("Please specify a serving size."))
		return
	}

	if err := s.DB.Save(&p).Error; err != nil {
		s.ReplyInternalError(msg, err)
		return
	}

	s.Reply(msg, sarif.CreateMessage("meal/product/created", &p))
}
예제 #27
0
func (s *Service) handleStats(msg sarif.Message) {
	f := ServingFilter{
		After:  time.Now().Truncate(24 * time.Hour).Add(5 * time.Hour),
		Before: time.Now().Truncate(24 * time.Hour).Add(29 * time.Hour),
	}
	if err := msg.DecodePayload(&f); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	var servings []*Serving
	if err := s.DB.Preload("Product").Scopes(applyFilter(f)).Order("time ASC").Preload("Product").Find(&servings).Error; err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	var stats ServingStats
	stats.Servings = servings
	for _, sv := range servings {
		stats.Add(sv.Stats())
	}
	s.Reply(msg, sarif.CreateMessage("meal/stats", stats))
}
예제 #28
0
func (s *Service) handleGeofenceCreate(msg sarif.Message) {
	var g Geofence
	if err := msg.DecodePayload(&g); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	if g.Address != "" {
		geo, err := Geocode(g.Address)
		if err != nil {
			s.ReplyBadRequest(msg, err)
			return
		}
		if len(geo) == 0 {
			s.Publish(msg.Reply(MsgAddressNotFound))
			return
		}
		g.BoundingBox = BoundingBox(geo[0].BoundingBox)
	}
	if g.Name == "" {
		g.Name = sarif.GenerateId()
	}
	g.GeohashMin = EncodeGeohash(g.BoundingBox.LatMin, g.BoundingBox.LngMin, 12)
	g.GeohashMax = EncodeGeohash(g.BoundingBox.LatMax, g.BoundingBox.LngMax, 12)

	if _, err := s.Store.Put(g.Key(), &g); err != nil {
		s.ReplyInternalError(msg, err)
	}

	reply := sarif.Message{Action: "location/fence/created"}
	if err := reply.EncodePayload(g); err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	reply.Text = "Geofence '" + g.Name + "' created."
	s.Publish(reply)
}
예제 #29
0
func (s *Service) handleLocationLast(msg sarif.Message) {
	filter := make(map[string]interface{})
	if err := msg.DecodePayload(&filter); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	s.Log("debug", "last loc request", filter)

	if err := s.fixFilters(filter); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	var last []Location
	err := s.Store.Scan("locations", store.Scan{
		Reverse: true,
		Only:    "values",
		Filter:  filter,
		Limit:   1,
	}, &last)
	if err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	if len(last) == 0 {
		s.Reply(msg, MsgNotFound)
		return
	}
	if last[0].Address == "" {
		// TODO: make optional
		if place, err := ReverseGeocode(last[0]); err == nil {
			last[0].Address = place.Pretty()
		}
	}

	s.Reply(msg, sarif.CreateMessage("location/found", last[0]))
}
예제 #30
0
func (s *Service) handleLocationList(msg sarif.Message) {
	filter := make(map[string]interface{})
	if err := msg.DecodePayload(&filter); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}
	if len(filter) == 0 {
		filter["time >="] = time.Now().Add(-24 * time.Hour).UTC().Format(time.RFC3339Nano)
	}
	s.Log("debug", "list loc request", filter)

	if err := s.fixFilters(filter); err != nil {
		s.ReplyBadRequest(msg, err)
		return
	}

	var last []*Location
	err := s.Store.Scan("locations", store.Scan{
		Reverse: true,
		Only:    "values",
		Filter:  filter,
	}, &last)
	if err != nil {
		s.ReplyInternalError(msg, err)
		return
	}
	if len(last) == 0 {
		s.Reply(msg, MsgNotFound)
		return
	}

	s.Reply(msg, sarif.CreateMessage("location/listed", &listPayload{
		len(last),
		last,
	}))
}