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, })) }
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()) } } }
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) }
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)) }
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)), })) }
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) }
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)) }
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, })) }
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)) }
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)) }
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) }
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)) }
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) } }
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 }
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)) }
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) }
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})) }
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)) }
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, })) }
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) }
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)) }
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)) }
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) }
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) } }
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)) }
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)) }
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)) }
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) }
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])) }
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, })) }