Beispiel #1
0
func (c *InternalCron) ScheduleEvent(ctx *core.Context, se *ScheduledEvent) error {
	sched, _, err := ParseSchedule(se.Schedule)
	if err != nil {
		return err
	}

	var event core.Map
	if err = json.Unmarshal([]byte(se.Event), &event); err != nil {
		return err
	}

	fn := func(t time.Time) error {
		loc := ctx.Location()
		if loc == nil {
			return errors.New("no location in ctx")
		}
		fr, err := loc.ProcessEvent(ctx, event)
		if err != nil {
			return err
		}
		core.Log(core.DEBUG|CRON, ctx, "InternalCron.ScheduleEvent", "findrules", *fr)
		return nil
	}
	return c.Cron.Add(ctx, se.Id, sched, fn)
}
Beispiel #2
0
func (s *Service) ProcessRequest(ctx *core.Context, m map[string]interface{}, out io.Writer) (map[string]interface{}, error) {
	core.Log(core.INFO, ctx, "service.ProcessRequest", "m", m)

	timer := core.NewTimer(ctx, "ProcessRequest")
	defer func() {
		elapsed := timer.Stop()
		core.Point(ctx, "rulesservice", "requestTime", elapsed/1000, "Microseconds")
	}()

	u, given := m["uri"]
	if !given {
		return nil, fmt.Errorf("No uri.")
	}

	uri := DWIMURI(ctx, u.(string))

	switch uri {

	// case "/api/sys/config":
	// 	mutationStore,have,_ := getStringParam(m, "MutationStore", false)
	// 	if have {
	// 		return fmt.Errorf("You can't do that.")
	// 	}

	// 	current s.System.GetConfig()

	// 	logging,have,_ := getStringParam(m, "logging", false)
	// 	if have {
	// 		current.Logging = logging
	// 	}
	// 	err := StoreConfig(current)
	// 	if err != nil {
	// 		return err
	// 	}
	// 	err = s.System.SetConfig(current)
	// 	if err != nil {
	// 		return err
	// 	}
	// 	return `{"status":"happy"}`

	case "/api/version":
		fmt.Fprintf(out, `{"version":"%s","go":"%s"}`,
			APIVersion,
			runtime.Version())

	case "/api/health":
		// Let's have a simple URI.
		fmt.Fprintf(out, `{"status":"good"}`)

	case "/api/health/shallow":
		fmt.Fprintf(out, `{"status":"good"}`)

	case "/api/health/deep":
		if err := s.HealthDeep(ctx); err != nil {
			return m, nil
		}
		fmt.Fprintf(out, `{"status":"good"}`)

	case "/api/health/deeper":
		if err := s.HealthDeeper(ctx); err != nil {
			return m, nil
		}
		fmt.Fprintf(out, `{"status":"good"}`)

	case "/api/sys/control":
		// Temporary implementation so I can test other things.
		control, given, _ := GetStringParam(m, "control", false)
		target := s.System.Control()
		if given {
			err := json.Unmarshal([]byte(control), target)
			if err != nil {
				return nil, err
			}
			s.System.SetControl(*target)

			target = s.System.Control()
			js, err := json.Marshal(target)
			if err != nil {
				return nil, err
			}
			out.Write([]byte(fmt.Sprintf(`{"result":"okay","control":%s}`, js)))
		} else {
			js, err := json.Marshal(target)
			if err != nil {
				return nil, err
			}
			out.Write(js)
		}

	case "/api/sys/params":
		control, given, _ := GetStringParam(m, "params", false)
		target := core.SystemParameters.Copy()
		if given {
			err := json.Unmarshal([]byte(control), target)
			if err != nil {
				return nil, err
			}
			core.SystemParameters = target

			target = core.SystemParameters
			js, err := json.Marshal(target)
			if err != nil {
				return nil, err
			}
			out.Write([]byte(fmt.Sprintf(`{"result":"okay","params":%s}`, js)))
		} else {
			js, err := json.Marshal(target)
			if err != nil {
				return nil, err
			}
			out.Write(js)
		}

	case "/api/sys/cachedlocations":
		js, err := json.Marshal(map[string]interface{}{
			"locations": s.System.GetCachedLocations(ctx),
		})
		if err != nil {
			return nil, err
		}
		out.Write(js)

	case "/api/sys/loccontrol":
		control, given, _ := GetStringParam(m, "control", false)
		ctl := s.System.Control()
		target := ctl.DefaultLocControl
		if given {
			err := json.Unmarshal([]byte(control), target)
			if err != nil {
				return nil, err
			}
			js, err := json.Marshal(target)
			if err != nil {
				return nil, err
			}
			ctl.DefaultLocControl = target
			out.Write([]byte(fmt.Sprintf(`{"result":"okay","control":%s}`, js)))
		} else {
			js, err := json.Marshal(target)
			if err != nil {
				return nil, err
			}
			out.Write(js)
		}

	case "/api/sys/stats":
		stats, err := s.System.GetStats(ctx)
		if err != nil {
			return nil, err
		}
		js, err := json.Marshal(&stats)
		if err != nil {
			return nil, err
		}
		out.Write(js)

	case "/api/sys/runtime":
		m, err := GetRuntimes(ctx)
		if nil != err {
			return nil, err
		}
		// m["stats"] = GetStats()

		js, err := json.Marshal(m)
		if err != nil {
			return nil, err
		}
		out.Write(js)

	case "/api/sys/util/nowsecs":
		fmt.Fprintf(out, `{"secs":%d}`, core.NowSecs())

	case "/api/sys/util/js":
		code, _, err := GetStringParam(m, "code", true)
		bs := make(core.Bindings)
		x, err := core.RunJavascript(ctx, &bs, nil, code)
		if err != nil {
			return m, err
		}
		js, err := json.Marshal(&x)
		if err != nil {
			return m, err
		}
		fmt.Fprintf(out, `{"result":%s}`, js)

	case "/api/sys/util/setJavascriptTestValue":
		js, _, err := GetStringParam(m, "value", true)
		if err != nil {
			return nil, err
		}
		var x interface{}
		if err := json.Unmarshal([]byte(js), &x); err != nil {
			return nil, err
		}
		core.JavascriptTestValue = x
		fmt.Fprintf(out, `{"result":%s}`, js)

	case "/api/sys/admin/panic": // No required params
		message, _, _ := GetStringParam(m, "message", false)
		panic(message)

	case "/api/sys/admin/sleep": // Option d=duration
		duration, given, _ := GetStringParam(m, "d", false)
		if !given {
			duration = "1s"
		}
		d, err := time.ParseDuration(duration)
		if err != nil {
			return nil, err
		}
		time.Sleep(d)
		out.Write([]byte(fmt.Sprintf(`{"slept":"%s"}`, d.String())))

	case "/api/sys/admin/shutdown":
		duration, given, _ := GetStringParam(m, "d", false)
		if given && s.Stopper == nil {
			return nil, errors.New("no Stopper for given duration")
		}
		if !given {
			duration = "1s"
		}
		d, err := time.ParseDuration(duration)
		if err != nil {
			return nil, err
		}

		go func() {
			if s.Stopper != nil {
				core.Log(core.INFO, ctx, "/api/admin/shutdown", "Stopper", true)
				if err := s.Stopper(ctx, d); err != nil {
					core.Log(core.ERROR, ctx, "/api/admin/shutdown", "error", err)
				}
			}
			core.Log(core.INFO, ctx, "/api/admin/shutdown", "Stopper", false)
			if err := s.Shutdown(ctx); err != nil {
				core.Log(core.ERROR, ctx, "/api/admin/shutdown", "error", err)
			}
		}()

		out.Write([]byte(`{"status":"okay"}`))

	case "/api/sys/admin/gcpercent":
		percent, _, _ := GetStringParam(m, "percent", true)
		n, err := strconv.Atoi(percent)
		if err != nil {
			return nil, err
		}
		was := debug.SetGCPercent(n)
		fmt.Fprintf(out, `{"status":"okay","was":%d,"now":%d}`, was, n)

	case "/api/sys/admin/freemem":
		debug.FreeOSMemory()
		fmt.Fprintf(out, `{"status":"okay"}`)

	case "/api/sys/admin/purgeslurpcache":
		core.SlurpCache.Purge()
		fmt.Fprintf(out, `{"status":"okay"}`)

	case "/api/sys/admin/purgehttppcache":
		core.HTTPClientCache.Purge()
		fmt.Fprintf(out, `{"status":"okay"}`)

	case "/api/sys/admin/purgecaches":
		core.SlurpCache.Purge()
		core.HTTPClientCache.Purge()
		fmt.Fprintf(out, `{"status":"okay"}`)

	case "/api/sys/admin/gc":
		runtime.GC()
		fmt.Fprintf(out, `{"status":"okay"}`)

	case "/api/sys/admin/heapdump":
		filename, _, _ := GetStringParam(m, "filename", false)
		if filename == "" {
			filename = "heap.dump"
		}
		f, err := os.Create(filename)
		if err != nil {
			return nil, err
		}
		debug.WriteHeapDump(f.Fd())
		if err = f.Close(); err != nil {
			return nil, err
		}
		fmt.Fprintf(out, `{"status":"okay","filename":"%s"}`, filename)

	case "/api/sys/util/match": // Params: fact or event,pattern
		fact, have, err := getMapParam(m, "fact", false)
		if err != nil {
			return nil, err
		}
		if !have {
			// Maybe we were given an 'event'.  Fine.
			fact, _, err = getMapParam(m, "event", true)
		}
		if err != nil {
			return nil, err
		}

		pattern, _, err := getMapParam(m, "pattern", true)
		if err != nil {
			return nil, err
		}

		bss, err := core.Matches(ctx, pattern, fact)
		if err != nil {
			return nil, err
		}

		js, err := json.Marshal(&bss)
		if err != nil {
			return nil, err
		}
		out.Write(js)

	case "/api/sys/admin/timers/names": // No params
		names := core.GetTimerNames()
		js, err := json.Marshal(names)
		if err != nil {
			return nil, err
		}
		out.Write(js)

	case "/api/sys/admin/timers/get":
		// Param: "name", optional "after" int, optional "limit" int

		name, _, err := GetStringParam(m, "name", true)
		if err != nil {
			return nil, err
		}
		after, given, _ := GetStringParam(m, "after", false)
		if !given {
			after = "-1"
		}

		aft, err := strconv.Atoi(after)
		if err != nil {
			return nil, err
		}

		limit, given := m["limit"]
		if !given {
			limit = float64(-1)
		}

		history := core.GetTimerHistory(name, aft, int(limit.(float64)))
		js, err := json.Marshal(history)
		if err != nil {
			return m, err
		}
		out.Write(js)

	case "/api/sys/storage/get": // For testing
		storage, err := s.System.PeekStorage(ctx)
		if err != nil {
			return nil, err
		}
		var acc string
		switch impl := storage.(type) {
		case *core.MemStorage:
			state := impl.State(ctx)
			js, err := json.Marshal(&state)
			if err != nil {
				acc = fmt.Sprintf(`{"type":"%T","error":"%s"}`,
					storage,
					err.Error())
			} else {
				acc = fmt.Sprintf(`{"type":"%T","state":%s}`,
					storage,
					js)
			}
		default:
			acc = fmt.Sprintf(`{"type":"%T"}`, storage)
		}
		if _, err = out.Write([]byte(acc)); err != nil {
			core.Log(core.ERROR, ctx, "/api/sys/storage", "error", err)
		}

	case "/api/sys/storage/set": // For testing
		state, _, err := getMapParam(m, "state", true)
		if err != nil {
			return nil, err
		}

		storage, err := s.System.PeekStorage(ctx)
		if err != nil {
			return nil, err
		}
		switch impl := storage.(type) {
		case *core.MemStorage:
			mms := make(map[string]map[string]string)
			for loc, pairs := range state {
				m, ok := pairs.(map[string]interface{})
				if !ok {
					return nil, fmt.Errorf("bad pairs %#v (%T)", pairs, pairs)
				}
				locPairs := make(map[string]string)
				for id, val := range m {
					s, ok := val.(string)
					if !ok {
						return nil, fmt.Errorf("bad value %#v (%T)", val, val)
					}
					locPairs[id] = s

				}
				mms[loc] = locPairs
			}
			impl.SetState(ctx, mms)
			out.Write([]byte(`{"status":"okay"}`))
		default:
			return nil, fmt.Errorf(`{"error":"set not supported for %T"}`, storage)
		}

	case "/api/sys/util/batch": // For testing
		// Execute a batch of requests
		batch, given := m["requests"]
		if !given {
			return nil, errors.New("missing 'requests' parameter")
		}
		var err error
		switch xs := batch.(type) {
		case []interface{}:
			_, err = out.Write([]byte("["))
			for i, x := range xs {
				if 0 < i {
					_, err = out.Write([]byte(","))
				}
				switch m := x.(type) {
				case map[string]interface{}:
					_, err = s.ProcessRequest(ctx, m, out)
					if err != nil {
						problem := fmt.Sprintf(`{"error":"%s"}`, err.Error())
						_, err = out.Write([]byte(problem))
					}
				default:
					problem := fmt.Sprintf(`"bad type %T"`, x)
					_, err = out.Write([]byte(problem))
				}
			}
			_, err = out.Write([]byte("]"))
		default:
			return nil, errors.New("'requests' not an array")
		}

		if err != nil {
			core.Log(core.ERROR, ctx, "/api/sys/batch", "error", err)
		}

	case "/api/loc/admin/size":
		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}
		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}
		n, err := s.System.GetSize(ctx, location)
		if err != nil {
			return nil, err
		}
		fmt.Fprintf(out, `{"size":%d}`, n)

	case "/api/loc/admin/stats":
		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		stats, err := s.System.GetLocationStats(ctx, location)
		if err != nil {
			return nil, err
		}
		js, err := json.Marshal(&stats)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/stats", "warning", err)
		}

	case "/api/loc/util/js":
		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		code, _, err := GetStringParam(m, "code", true)

		encoding, provided, err := GetStringParam(m, "encoding", false)
		if provided {
			code, err = core.DecodeString(encoding, code)
			if err != nil {
				return nil, err
			}
		}

		bs := make(core.Bindings)

		var props map[string]interface{}
		ctl := s.System.LocControl(ctx, location)
		if ctl != nil {
			props = ctl.CodeProps
		}

		libraries := make([]string, 0, 0)
		libs, given := m["libraries"]
		if given {
			switch vv := libs.(type) {
			case []interface{}:
				for _, lib := range vv {
					switch s := lib.(type) {
					case string:
						libraries = append(libraries, s)
					default:
						err := fmt.Errorf("Bad library type %T (value= %#v)", lib, lib)
						core.Log(core.UERR, ctx, "/api/loc/util/js", "error", err)
						return nil, err
					}
				}
			default:
				err := fmt.Errorf("Bad 'libraries' type %T (value= %#v)",
					libs, libs)
				core.Log(core.UERR, ctx, "/api/loc/util/js", "error", err)
				return nil, err
			}
		}

		x, err := s.System.RunJavascript(ctx, location, code, libraries, &bs, props)
		if err != nil {
			return m, err
		}

		js, err := json.Marshal(&x)
		if err != nil {
			return m, err
		}
		fmt.Fprintf(out, `{"result":%s}`, js)

	case "/api/loc/admin/create": // Params: location
		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		created, err := s.System.CreateLocation(ctx, location)
		if err != nil {
			return nil, err
		}
		if !created {
			return nil, fmt.Errorf("%s already exists", location)
		}
		if _, err = out.Write([]byte(`{"status":"okay"}`)); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/admin/create", "warning", err)
		}

	case "/api/loc/admin/clear": // Params: location
		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		err = s.System.ClearLocation(ctx, location)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write([]byte(`{"status":"okay"}`)); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/admin/clear", "warning", err)
		}

	case "/api/loc/admin/updatedmem": // Params: location
		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		updated, err := s.System.GetLastUpdatedMem(ctx, location)
		if err != nil {
			return nil, err
		}

		resp := fmt.Sprintf(`{"lastUpdated":"%s","source":"memory"}`, updated)
		if _, err = out.Write([]byte(resp)); err != nil {
			core.Log(core.INFO, ctx, "/api/loc/admin/updatedmem", "warning", err)
		}

	case "/api/loc/admin/delete": // Params: location
		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		err = s.System.DeleteLocation(ctx, location)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write([]byte(`{"status":"okay"}`)); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/admin/delete", "warning", err)
		}

	case "/api/loc/events/ingest": // Params: event
		event, _, err := getMapParam(m, "event", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		// ToDo: Not this.
		js, err := json.Marshal(event)
		if err != nil {
			return nil, err
		}

		ctx.LogAccumulatorLevel = core.EVERYTHING
		work, err := s.System.ProcessEvent(ctx, location, string(js))
		if err != nil {
			return nil, err
		}

		js, err = json.Marshal(work)
		if err != nil {
			return nil, err
		}

		s := fmt.Sprintf(`{"id":"%s","result":%s}`, ctx.Id(), js)
		core.Log(core.INFO, ctx, "/api/loc/events/ingest", "got", s)
		if _, err = out.Write([]byte(s)); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/events/ingest", "warning", err)
		}

	case "/api/loc/events/retry": // Params: work
		workStr, _, err := GetStringParam(m, "work", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		fr := core.FindRules{}
		err = json.Unmarshal([]byte(workStr), &fr)
		if err != nil {
			return nil, err
		}

		ctx.LogAccumulatorLevel = core.EVERYTHING
		// ToDo: Support number of steps to take.
		err = s.System.RetryEventWork(ctx, location, &fr)
		js, err := json.Marshal(fr)
		if err != nil {
			return nil, err
		}

		s := fmt.Sprintf(`{"id":"%s","result":%s}`, ctx.Id(), js)
		core.Log(core.INFO, ctx, "/api/loc/events/retry", "got", s)
		if _, err = out.Write([]byte(s)); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/events/retry", "warning", err)
		}

	case "/api/loc/facts/add": // Params: fact
		fact, _, err := getMapParam(m, "fact", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		id, _, err := GetStringParam(m, "id", false)

		// ToDo: Not this.
		js, err := json.Marshal(fact)
		if err != nil {
			return nil, err
		}

		id, err = s.System.AddFact(ctx, location, id, string(js))
		if err != nil {
			return nil, err
		}
		m := map[string]interface{}{"id": id}

		js, err = json.Marshal(&m)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/facts/add", "warning", err)
		}

	case "/api/loc/facts/rem": // Params: id
		id, _, err := GetStringParam(m, "id", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		rid, err := s.System.RemFact(ctx, location, id)
		if err != nil {
			return nil, err
		}
		m := map[string]interface{}{"removed": rid, "given": id}

		js, err := json.Marshal(&m)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/facts/rem", "warning", err)
		}

	case "/api/loc/facts/get": // Params: id
		id, _, err := GetStringParam(m, "id", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		js, err := s.System.GetFact(ctx, location, id)
		if err != nil {
			return nil, err
		}
		bs := []byte(fmt.Sprintf(`{"fact":%s,"id":"%s"}`, js, id))

		if _, err = out.Write(bs); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/facts/get", "warning", err)
		}

	case "/api/loc/facts/search": // Params: pattern, inherited
		pattern, _, err := getMapParam(m, "pattern", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		includedInherited, _, err := getBoolParam(m, "inherited", false)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		// ToDo: Not this.
		js, err := json.Marshal(pattern)
		if err != nil {
			return nil, err
		}

		sr, err := s.System.SearchFacts(ctx, location, string(js), includedInherited)
		if err != nil {
			return nil, err
		}

		_, take := m["take"]
		if take {
			// Warning: Not (yet) atomic!
			for _, found := range sr.Found {
				_, err := s.System.RemFact(ctx, location, found.Id)
				if err != nil {
					core.Log(core.ERROR, ctx, "service.ProcessRequest", "app_tag", "/api/loc/facts/search", "error", err, "RemFact", found.Id)
				}
				// ToDo: Something with error.
			}
		}

		js, err = json.Marshal(sr)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/facts/take", "warning", err)
		}

	case "/api/loc/facts/take": // Params: pattern
		m["uri"] = "/api/loc/facts/search"
		m["take"] = true
		s.ProcessRequest(ctx, m, out)

	case "/api/loc/facts/replace": // Params: pattern, fact
		// Really a 'take' followed by a 'add'.
		m["uri"] = "/api/loc/facts/search"
		m["take"] = true
		core.Log(core.INFO, ctx, "service.ProcessRequest", "app_tag", "/api/loc/facts/replace", "phase", "take")
		s.ProcessRequest(ctx, m, ioutil.Discard)

		core.Log(core.INFO, ctx, "service.ProcessRequest", "app_tag", "/api/loc/facts/replace", "phase", "add")
		m["uri"] = "/api/loc/facts/add"
		s.ProcessRequest(ctx, m, out)

	case "/api/loc/facts/query": // Params: query
		query, _, err := getMapParam(m, "query", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		// ToDo: Not this.
		js, err := json.Marshal(query)
		if err != nil {
			return nil, err
		}

		qr, err := s.System.Query(ctx, location, string(js))
		if err != nil {
			return nil, err
		}

		js, err = json.Marshal(qr)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/facts/query", "warning", err)
		}

	case "/api/loc/rules/list": // Params: inherited
		location, _, err := GetStringParam(m, "location", true)
		if nil != err {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		includedInherited, _, err := getBoolParam(m, "inherited", false)
		if err != nil {
			return nil, err
		}

		ss, err := s.System.ListRules(ctx, location, includedInherited)
		if nil != err {
			return nil, err
		}

		js, err := json.Marshal(map[string][]string{"ids": ss})
		if nil != err {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/rules/list", "warning", err)
		}

	case "/api/loc/rules/add": // Params: rule
		rule, _, err := getMapParam(m, "rule", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		id, _, err := GetStringParam(m, "id", false)

		// ToDo: Not this.
		js, err := json.Marshal(rule)
		if err != nil {
			return nil, err
		}

		id, err = s.System.AddRule(ctx, location, id, string(js))
		if err != nil {
			return nil, err
		}
		m := map[string]interface{}{"id": id}

		js, err = json.Marshal(&m)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/rules/add", "warning", err)
		}

	case "/api/loc/rules/rem": // Params: id
		id, _, err := GetStringParam(m, "id", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		rid, err := s.System.RemRule(ctx, location, id)
		if err != nil {
			return nil, err
		}
		m := map[string]interface{}{"removed": rid, "given": id}

		js, err := json.Marshal(&m)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/rules/rem", "warning", err)
		}

	case "/api/loc/rules/disable": // Params: id
		id, _, err := GetStringParam(m, "id", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		err = s.System.EnableRule(ctx, location, id, false)
		if err != nil {
			return nil, err
		}
		m := map[string]interface{}{"disabled": id}

		js, err := json.Marshal(&m)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/rules/disable", "warning", err)
		}

	case "/api/loc/rules/enable": // Params: id
		id, _, err := GetStringParam(m, "id", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		err = s.System.EnableRule(ctx, location, id, true)
		if err != nil {
			return nil, err
		}
		m := map[string]interface{}{"enabled": id}

		js, err := json.Marshal(&m)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/rules/enable", "warning", err)
		}

	case "/api/loc/rules/enabled": // Params: id
		id, _, err := GetStringParam(m, "id", true)
		if err != nil {
			return nil, err
		}

		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		enabled, err := s.System.RuleEnabled(ctx, location, id)
		if err != nil {
			return nil, err
		}
		m := map[string]interface{}{"ruleId": id, "enabled": enabled}

		js, err := json.Marshal(&m)
		if err != nil {
			return nil, err
		}
		if _, err = out.Write(js); err != nil {
			core.Log(core.ERROR, ctx, "/api/loc/rules/enabled", "warning", err)
		}

	case "/api/loc/parents": // Params: none means get; "set=[x,y]" means set.
		location, _, err := GetStringParam(m, "location", true)
		if err != nil {
			return nil, err
		}

		if err := s.checkLocal(ctx, location); err != nil {
			return nil, err
		}

		js, given, err := GetStringParam(m, "set", false)

		if given {
			var parents []string
			if err = json.Unmarshal([]byte(js), &parents); err != nil {
				return nil, err
			}

			_, err := s.System.SetParents(ctx, location, parents)
			if err != nil {
				return nil, err
			}
			js := fmt.Sprintf(`{"result": %s}`, js)
			if _, err = out.Write([]byte(js)); err != nil {
				core.Log(core.ERROR, ctx, "/api/loc/parents/set", "warning", err)
			}
		} else {
			ps, err := s.System.GetParents(ctx, location)
			if err != nil {
				return nil, err
			}
			bs, err := json.Marshal(&ps)
			if err != nil {
				return nil, err
			}
			bs = []byte(fmt.Sprintf(`{"result":%s}`, bs))
			if _, err = out.Write(bs); err != nil {
				core.Log(core.ERROR, ctx, "/api/loc/parents/get", "warning", err)
			}
		}

	default:
		return nil, fmt.Errorf("Unknown URI '%s'", u)

	}

	return nil, nil
}
Beispiel #3
0
func AddHooks(ctx *core.Context, cronner Cronner, state core.State) error {

	add := func(ctx *core.Context, state core.State, id string, fact core.Map, loading bool) error {

		if cronner.Persistent() && loading {
			return nil
		}

		schedule, err := getSchedule(ctx, fact)
		if err != nil {
			return err
		}

		if schedule == "" {
			return nil
		}

		if cronner == nil {
			return errors.New("no cron available")
		}

		location := ctx.Location().Name

		core.Log(core.INFO|CRON, ctx, "addHook", "id", id, "location", location, "schedule", schedule)

		event := fmt.Sprintf(`{"trigger!":"%s"}`, id)

		se := &ScheduledEvent{
			Id:       id,
			Event:    event,
			Schedule: schedule,
		}

		if err = cronner.ScheduleEvent(ctx, se); err != nil {
			core.Log(core.WARN|CRON, ctx, "addHook", "id", id, "error", err)
			return err
		}

		return nil
	}

	state.AddHook(add)

	rem := func(ctx *core.Context, state core.State, id string) error {
		core.Log(core.INFO|CRON, ctx, "remHook", "id", id)

		// Sad that we have to get the whole fact.

		// Yikes!  The caller of this hook already has the state lock!
		fact, err := state.Get(ctx, id)
		if err != nil {
			return err
		}
		if fact == nil {
			core.Log(core.WARN|CRON, ctx, "remHook", "missing", id)
			return nil
		}

		schedule, err := getSchedule(ctx, fact)
		if err != nil {
			return err
		}
		if schedule == "" {
			return nil
		}

		if cronner == nil {
			return errors.New("no cron available")
		}

		_, err = cronner.Rem(ctx, id)

		return err
	}
	state.RemHook(rem)

	return nil
}