// Recursively resolve pointers to other factoids func recurse(fact *factoids.Factoid, keys map[string]bool) { val := fact.Value key, start, end := util.FactPointer(val) if key == "" { return } if _, ok := keys[key]; ok || len(keys) > 20 { fact.Value = val[:start] + "[circular reference]" + val[end:] return } keys[key] = true if f2 := fc.GetPseudoRand(key); f2 != nil { fact.Value = val[:start] + f2.Value + val[end:] if start == 0 && fact.Type != f2.Type { // Propagate change of factoid type when the pointer // is at the beginning of the string. fact.Type = f2.Type } recurse(fact, keys) return } // if we get here, we found a pointer key but no matching factoid // so recurse on the stuff after that key *only* to avoid loops. fact.Value = val[end:] recurse(fact, keys) fact.Value = val[:end] + fact.Value }
func lookup(line *base.Line) { // Only perform extra prefix removal if we weren't addressed directly key := ToKey(line.Args[1], !line.Addressed) var fact *factoids.Factoid if fact = fc.GetPseudoRand(key); fact == nil && line.Cmd == "ACTION" { // Support sp0rkle's habit of stripping off it's own nick // but only for actions, not privmsgs. if strings.HasSuffix(key, bot.Nick()) { key = strings.TrimSpace(key[:len(key)-len(bot.Nick())]) fact = fc.GetPseudoRand(key) } } if fact == nil { return } // Chance is used to limit the rate of factoid replies for things // people say a lot, like smilies, or 'lol', or 'i love the peen'. chance := fact.Chance if key == "" { // This is doing a "random" lookup, triggered by someone typing in // something entirely composed of the chars stripped by ToKey(). // To avoid making this too spammy, forcibly limit the chance to 40%. chance = 0.4 } if rand.Float64() < chance { // Store this as the last seen factoid LastSeen(line.Args[0], fact.Id) // Update the Accessed field // TODO(fluffle): fd should take care of updating Accessed internally fact.Access(line.Storable()) // And store the new factoid data if err := fc.Update(bson.M{"_id": fact.Id}, fact); err != nil { bot.ReplyN(line, "I failed to update '%s' (%s): %s ", fact.Key, fact.Id, err) } keys := map[string]bool{key: true} val := recurse(fact.Value, keys) switch fact.Type { case factoids.F_ACTION: bot.Do(line, "%s", val) default: bot.Reply(line, "%s", val) } } }