Esempio n. 1
0
func (s *HTTPService) Start(ctx *core.Context, servicePort string) error {

	server := &http.Server{
		Handler: s,
		// ReadTimeout:    60 * time.Second,
		// WriteTimeout:   60 * time.Second,
		MaxHeaderBytes: 1 << 20,
		ConnState: func(c net.Conn, state http.ConnState) {
			s.connStates.Inc(state.String())
			loc := c.LocalAddr()
			rem := c.RemoteAddr()
			core.Log(core.INFO, ctx, "service.Server", "conn", c, "state", state, "local", loc, "remote", rem)
		},
	}
	core.Log(core.INFO, ctx, "service.HTTPService", "port", servicePort)

	if !BeGraceful {
		return server.ListenAndServe()
	} else {
		l, err := NewListener(ctx, s, servicePort, false)
		if err != nil {
			return err
		}
		s.Service.Stopper = func(ctx *core.Context, d time.Duration) error {
			return l.Stop(d)
		}
		server.Serve(l)
		n := l.Drain(5 * time.Second)
		if n == 0 {
			return nil
		}
		return fmt.Errorf("killing %d pending requests", n)
	}
}
Esempio n. 2
0
func (c *Cron) schedule(ctx *core.Context, job *CronJob, checkLimit bool) error {
	core.Log(core.INFO|CRON, ctx, "Cron.schedule", "job", *job, "name", c.Name)

	if job.Expression != nil {
		job.Next = job.Expression.Next(time.Now().UTC())
	}

	c.Lock()

	//remove existing job with the same id
	if _, err := c.rem(ctx, job.Id); nil != err {
		c.Unlock()
		core.Log(core.WARN|CRON, ctx, "Cron.schedule", "error", err)
		return err
	}

	var err error
	if checkLimit {
		count := len(c.Timeline)
		limit := c.Limit
		if limit <= count {
			err = fmt.Errorf("Cron %p %s capacity limit (%d) hit", c, c.Name, limit)
			core.Log(core.WARN|CRON, ctx, "Cron.schedule", "limit", limit, "error", err, "name", c.Name)
		}
	}
	if err == nil {
		c.insert(ctx, job)
	}

	c.Unlock()
	return err
}
Esempio n. 3
0
func (l *Listener) Accept() (c net.Conn, err error) {
	select {
	case op := <-l.ctl:
		core.Log(core.INFO, l.ctx, "service.Listener", "op", op)
		l.mode = op
	default:
	}

	if !l.admin {
		maxed, n := l.service.Maxed()

		switch l.mode {
		case "stop":
			err := fmt.Errorf("service stopping (%d)", n)
			core.Log(core.INFO, l.ctx, "service.Listener", "stopping", n)
			return nil, err
		case "stopped":
			err := fmt.Errorf("service stopped")
			core.Log(core.INFO, l.ctx, "service.Listener", "stopped", n)
			return nil, err
		case "":
		default:
			core.Log(core.WARN, l.ctx, "service.Listener", "mode", l.mode)
		}

		if maxed {
			err := fmt.Errorf("too many connections: %d", n)
			core.Log(core.WARN, l.ctx, "service.Listener", "error", err)
			tooMany(c)
			return nil, TooManyConnections
		}
	}

	return l.l.Accept()
}
Esempio n. 4
0
func (l *Listener) Stop(d time.Duration) error {

	core.Log(core.INFO, l.ctx, "service.Listener.Stop")
	l.ctl <- "stop"

	n := l.Drain(d)
	core.Log(core.INFO, l.ctx, "service.Listener.Stop", "pending", n)
	l.mode = "stopped"

	return nil
}
Esempio n. 5
0
// Start starts up a goroutine that operates the cron system.
//
// This method returns after the goroutine is started.
//
// You need to call this method for the cron system to run any jobs.
func (c *Cron) Start(ctx *core.Context) {
	core.Log(core.INFO|CRON, ctx, "Cron.Start", "name", c.Name)
	go func() {
		err := c.start(ctx)
		// Make sure we log any trouble.
		if err != nil {
			core.Log(core.CRIT|CRON, ctx, "Cron.Start", "error", err, "name", c.Name)
		}
	}()
	// ToDo: Try to make sure we are in the select loop before returning here.
	c.Resume(ctx)
}
Esempio n. 6
0
func (s *Service) HealthDeeper(ctx *core.Context) error {
	core.Log(core.INFO, ctx, "HealthDeeper")
	err := s.HealthDeep(ctx)
	if err == nil {
		core.Log(core.INFO, ctx, "HealthDeeper", "looking", "storage")
		storage, err := s.System.PeekStorage(ctx)
		if err == nil && storage != nil {
			core.Log(core.INFO, ctx, "HealthDeeper", "checking", "storage")
			err = storage.Health(ctx)
		}
	}
	core.Log(core.INFO, ctx, "HealthDeeper", "err", err)
	return err
}
Esempio n. 7
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)
}
Esempio n. 8
0
func (s *Service) HealthDeep(ctx *core.Context) error {
	core.Log(core.INFO, ctx, "HealthDeep")
	// Just try some Javascript.
	code := "'go' + 'od'"
	x, err := core.RunJavascript(ctx, nil, nil, code)
	if err == nil {
		var js []byte
		js, err = json.Marshal(&x)
		if err == nil {
			if string(js) != `"good"` {
				err = fmt.Errorf("Unexpected %s", js)
			}
		}
	}

	core.Log(core.INFO, ctx, "HealthDeep", "err", err)
	return err
}
Esempio n. 9
0
func (s *Service) Shutdown(ctx *core.Context) error {
	core.Log(core.WARN, ctx, "Service.Shutdown")
	storage, err := s.System.PeekStorage(ctx)
	if err != nil {
		return err
	}
	if storage != nil {
		core.Log(core.WARN, ctx, "Service.Shutdown", "closing", "storage")
		err = storage.Close(ctx)
		if err != nil {
			return err
		}
	}
	rc := 0
	if err != nil {
		rc = 1
	}
	os.Exit(rc)
	return nil
}
Esempio n. 10
0
// control is the low-level method for controlling the Cron instance.
//
// Gets the lock and sends the given command to the Cron's control channel.
func (c *Cron) command(ctx *core.Context, command string) error {
	core.Log(core.INFO|CRON, ctx, "Cron.command", "command", command, "name", c.Name)
	c.Lock()
	if c.control == nil {
		c.Unlock()
		return fmt.Errorf("Not started")
	}
	c.control <- command
	c.Unlock()
	return nil
}
Esempio n. 11
0
func (l *Listener) Drain(d time.Duration) int {
	pause := 1 * time.Second

	waited := time.Duration(0)
	var n int32
	for i := 0; true; i++ {
		_, n = l.service.Maxed()
		core.Log(core.INFO, l.ctx, "service.Listener.Stop", "loop", i, "pending", n, "waited", waited.String())

		if n <= 0 {
			break
		}
		time.Sleep(pause)
		waited += pause
		if d <= waited {
			break
		}
	}
	core.Log(core.INFO, l.ctx, "service.Listener.Stop", "pending", n, "waited", waited.String())
	return int(n)
}
Esempio n. 12
0
func (c *InternalCron) Schedule(ctx *core.Context, sw *ScheduledWork) error {

	sched, _, err := ParseSchedule(sw.Schedule)
	if err != nil {
		return err
	}

	fn := func(t time.Time) error {
		buf := strings.NewReader(sw.Body)
		req, err := http.NewRequest(sw.Method, sw.URL, buf)
		id := sw.Id

		if err != nil {
			core.Log(core.WARN|CRON, ctx, "InternalCron.Schedule", "id", id, "error", err)
			return err
		}

		for header, val := range sw.Headers {
			req.Header.Set(header, val)
		}

		// ToDo: Don't use stock http.DefaultClient.
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			core.Log(core.WARN|CRON, ctx, "InternalCron.Schedule", "id", id, "error", err)
			return err
		}

		_, err = ioutil.ReadAll(resp.Body)
		// ToDo: At least log what we got.
		if err != nil {
			core.Log(core.WARN|CRON, ctx, "ExternalCron.Schedule", "id", id, "error", err)
			return err
		}

		return nil
	}

	return c.Cron.Add(ctx, sw.Id, sched, fn)
}
Esempio n. 13
0
func (c *Cron) run(ctx *core.Context, job *CronJob) {
	core.Log(core.INFO|CRON, ctx, "Cron.run", "job", *job, "name", c.Name)
	once := job.Once()
	err := job.Fn(time.Now())
	if err != nil {
		job.Err = err
	}
	if once {
	} else {
		// ToDo: Consider an error here.
		c.schedule(ctx, job, false)
	}
}
Esempio n. 14
0
func (c *Cron) insert(ctx *core.Context, job *CronJob) int {
	core.Log(core.INFO|CRON, ctx, "Cron.insert", "job", *job, "name", c.Name)
	// Assumes we have the lock.
	at := c.Timeline.Search(job.Next)
	if at == len(c.Timeline) {
		c.Timeline = append(c.Timeline, job)
	} else {
		c.Timeline = append(c.Timeline, nil)
		copy(c.Timeline[at+1:], c.Timeline[at:])
		c.Timeline[at] = job
	}
	c.resetTimer()
	return at
}
Esempio n. 15
0
// Add creates a new cron job.
//
// Use the ID to Rem() that job later if you want.  F is the work to
// be performed.  The first argument is the scheduled time for that
// invocation, and the second argument is true if the job is a
// one-shot job.
//
// The schedule syntax can have three forms:
//
// 1. A cron schedule string (supposedly in syntax at
// https://en.wikipedia.org/wiki/Cron).
//
// 2. "!TIME", where TIME is according to RFC3339.
//
// 3. "+DURATION", where DURATION is a Go Duration
// (http://golang.org/pkg/time/#ParseDuration).  Examples: "5s" means
// "5 seconds", "2m" means "2 minutes", and "1h" means "1 hour".
func (c *Cron) Add(ctx *core.Context, id string, schedule string, f func(t time.Time) error) error {
	core.Log(core.INFO|CRON, ctx, "Cron.Add", "id", id, "schedule", schedule, "name", c.Name)
	job := CronJob{}
	job.Id = id
	job.Schedule = schedule
	job.Fn = f
	if core.OneShotSchedule(schedule) {
		switch schedule[0:1] {
		case "!":
			t, err := time.Parse(time.RFC3339, schedule[1:])
			if err != nil {
				return err
			}
			job.Next = t
		case "+":
			d, err := time.ParseDuration(schedule[1:])
			if err != nil {
				return err
			}
			job.Next = time.Now().Add(d)
		default:
			return fmt.Errorf("bad one-shot schedule '%s'", schedule)
		}
	} else {
		expr, err := cronexpr.Parse(schedule)
		if err != nil {
			return err
		}
		job.Expression = expr
	}

	future := job.Next.Sub(time.Now())
	core.Log(core.DEBUG|CRON, ctx, "Cron.Add", "id", id, "in", future)

	return c.schedule(ctx, &job, true)
}
Esempio n. 16
0
func (c *Cron) rem(ctx *core.Context, id string) (bool, error) {
	core.Log(core.INFO|CRON, ctx, "Cron.rem", "id", id, "name", c.Name)
	found := false
	for at, job := range c.Timeline {
		if job.Id == id {
			copy(c.Timeline[at:], c.Timeline[at+1:])
			c.Timeline = c.Timeline[0 : len(c.Timeline)-1]
			found = true
			break
		}
	}
	if !found {
		// log.Printf("Cron.Rem %p %s job %s not found", c, c.Name, id)
	}
	return found, nil
}
Esempio n. 17
0
func DWIMURI(ctx *core.Context, uri string) string {
	// http://en.wikipedia.org/wiki/DWIM

	// Clean up URI to help with dispatch.

	// We have "/api" in front of all our APIs can their calls to
	// make it easier to search/replace those names in code and
	// docs.

	given := uri
	dropParams, _ := regexp.Compile("[?].*")
	uri = dropParams.ReplaceAllString(uri, "")
	// Strip any pesky version, which we can ignore at the momemnt.
	dropVersion, _ := regexp.Compile("^/v?[.0-9]+")
	uri = dropVersion.ReplaceAllString(uri, "")
	if !strings.HasPrefix(uri, "/api") {
		uri = "/api" + uri
	}
	core.Log(core.DEBUG, ctx, "service.DWIMURI", "from", given, "to", uri)
	return uri
}
Esempio n. 18
0
func GetHTTPRequest(ctx *core.Context, r *http.Request) (map[string]interface{}, error) {

	uri := DWIMURI(ctx, r.URL.String())
	core.Log(core.INFO, ctx, "service.GetHTTPRequest", "method", r.Method, "uri", uri)

	m := make(map[string]interface{})

	parseQuery := func(q string) error {
		qvs, err := url.ParseQuery(q)
		if err != nil {
			return err
		}
		for p, vs := range qvs {
			if len(vs) != 1 {
				return fmt.Errorf("need exactly one value (not %d) for %s", len(vs), p)
			}
			var v interface{}
			if v, err = parseParameter(p, vs[0]); err != nil {
				return err
			}
			m[p] = v
		}
		return nil
	}

	if err := parseQuery(r.URL.RawQuery); err != nil {
		return nil, err
	}

	var err error
	switch uri {
	case "/api/json", "/api/yaml":
		var err error
		switch r.Method {
		case "POST":
			var js []byte
			if js, err = ioutil.ReadAll(r.Body); err != nil {
				return nil, err
			}
			switch uri {
			case "/api/json":
				if err = json.Unmarshal(js, &m); err != nil {
					return nil, err
				}
			case "/api/yaml":
				if err = UnmarshalYAML(js, &m); err != nil {
					return nil, err
				}
			}
			given, have := m["uri"]
			if !have {
				return nil, fmt.Errorf("no uri given by %s", js)
			}
			var ok bool
			uri, ok = given.(string)
			if !ok {
				return nil, fmt.Errorf("need a string uri, not a %T (%s)", given, given)
			}
		default:
			return nil, errors.New("no uri given")
		}

	default:
		m["uri"] = r.URL.Path

		switch r.Method {
		case "POST":
			var js []byte
			if js, err = ioutil.ReadAll(r.Body); err != nil {
				return nil, err
			}

			if js[0] == '{' {
				// If the body looks like JSON, treat it as JSON.
				if err = json.Unmarshal(js, &m); err != nil {
					return nil, err
				}
			} else if MaybeYAML(js) {
				if err = UnmarshalYAML(js, &m); err != nil {
					return nil, err
				}
			} else {
				// Try to parse a form.
				if err := parseQuery(string(js)); err != nil {
					return nil, err
				}
			}
		}
	}

	io.Copy(ioutil.Discard, r.Body)

	core.Log(core.INFO, ctx, "service.GetHTTPRequest", "m", m)
	return m, nil
}
Esempio n. 19
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
}
Esempio n. 20
0
// start launches the instance's processing loop.
func (c *Cron) start(ctx *core.Context) error {
	core.Log(core.INFO|CRON, ctx, "Cron.start", "name", c.Name)

	// Make a control channel.
	c.Lock()
	if c.control != nil {
		c.Unlock()
		return fmt.Errorf("Already started")
	}
	c.control = make(chan string, 10)
	c.Unlock()

	// Either a broadcast or a local command can suspend or resume the loop.
	// Might want separate state.
	suspendedLocally := false

	// We'll receive a broadcast on this channel.
	broadcast, suspendedByBroadcast := c.broadcaster.Get()
	if suspendedByBroadcast {
		suspendedLocally = true
		c.stopTimerLocked()
	}
LOOP:
	for {
		select {

		case <-(*broadcast):
			// Channel closed.  Toggle our state.
			// Get the (new) control channel since our pointer now points to a dead one.
			broadcast, suspendedByBroadcast = c.broadcaster.Get()
			if suspendedByBroadcast {
				suspendedLocally = true
				c.stopTimerLocked()
			} else if suspendedLocally {
				suspendedLocally = false
				c.resetTimerLocked()
			}

		case command := <-c.control:
			var err error
			switch command {
			case "pause":
				c.stopTimerLocked()
				time.Sleep(c.PauseDuration)
				c.resetTimerLocked()
			case "suspend":
				suspendedLocally = true
				c.stopTimerLocked()
				continue
			case "resume":
				if suspendedLocally {
					suspendedLocally = false
					c.resetTimerLocked()
				}
			case "kill":
				// Danger.  Can't restart from the control channel.
				c.stopTimerLocked()
				break LOOP
			default:
				err = fmt.Errorf("Cron %p %s unknown command '%s'", c, c.Name, command)
				core.Log(core.WARN|CRON, ctx, "Cron.start", "error", err, "name", c.Name)
				return err
			}

		case <-c.timer.C:

			// Let's check how well our timer is working.
			// delta := time.Now().Sub(c.timerTarget)

			now := time.Now()
			c.Lock()
			if 0 < len(c.Timeline) {
				job := c.Timeline[0]
				ready := !now.Before(job.Next)
				if ready {
					// Danger.  ToDo: Be more careful
					c.Timeline = c.Timeline[1:]
					go func(job *CronJob) {
						c.run(ctx, job)
					}(job)
					c.resetTimer()
				}
			}
			c.Unlock()
			// elapsed := time.Now().Sub(now)
		}
	}

	c.Lock()
	c.control = nil
	c.Unlock()
	return nil
}
Esempio n. 21
0
func (s *HTTPService) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	s.incPending(true)
	ctx := s.Ctx.SubContext()

	timer := core.NewTimer(ctx, "ServeHTTP")

	defer func() {
		if r.Body != nil {
			if err := r.Body.Close(); err != nil {
				core.Log(core.WARN, nil, "ServerHTTP", "error", err, "when", "Close")
			}
		}
		s.incPending(false)
		timer.Stop()

	}()

	m, err := GetHTTPRequest(ctx, r)

	if err != nil {
		core.Log(core.ERROR, ctx, "service.ServeHTTP", "error", err)
		protest(ctx, err, w)
		return
	}

	switch DWIMURI(ctx, m["uri"].(string)) { // Sorry.
	case "/api/sys/admin/connstates":
		counts := s.connStates.Get()
		js, err := json.Marshal(&counts)
		if err != nil {
			w.Write([]byte(err.Error()))
			return
		}
		w.Write(js)
		return

	case "/api/sys/admin/pending":
		max, given := m["max"]
		if given {
			str, ok := max.(string)
			if !ok {
				protest(ctx, err, w)
				return
			}
			n, err := strconv.Atoi(str)
			if err != nil {
				protest(ctx, err, w)
				return
			}
			s.SetMaxPending(int32(n))
		}
		maxed, pending := s.Maxed()
		w.Write([]byte(fmt.Sprintf(`{"pending":%d, "max":%d, "maxed":%v}`, pending, s.MaxPending(), maxed) + "\n"))
		return
	}

	_, err = s.Service.ProcessRequest(ctx, m, w)
	if err != nil {
		if redirect, is := err.(*Redirect); is {
			core.Log(core.INFO, ctx, "service.ServeHTTP", "redirect", redirect.To)
			http.Redirect(w, r, "http://"+redirect.To, 301)
			return
		} else {
			core.Log(core.ERROR, ctx, "service.ServeHTTP", "error", err)
			protest(ctx, err, w)
		}
	}
	w.Write([]byte{byte('\n')})
}
Esempio n. 22
0
func (s *HTTPService) SetMaxPending(max int32) {
	core.Log(core.INFO, nil, "service.HTTPService", "maxPending", max)
	atomic.StoreInt32(&s.maxPending, max)
}
Esempio n. 23
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
}