// StartService starts the specified service. The operation parameter is used // for the context of the start; the service's URI, the referrer, signaling // completion of the service start, etc. // // Upon returning, either the operation has failed, or the service is still // going through the motions of being started. In the latter case, the caller // can wait for completion of the operation to ensure the service is fully // started. // func (h *ServiceHost) StartService(op *operation.Operation, s Service) { s.SetHost(h) // The selflink is expected to be either set on the service externally // (before starting the service), or as the URI path on the operation. selfLink := s.SelfLink() if selfLink == "" { // Prefix path with / to make sure it is absolute. // The clean function removes double /'s and the trailing /, if any. selfLink = path.Clean("/" + op.GetURI().Path) s.SetSelfLink(selfLink) } // Add service to the host's service map. h.Lock() _, ok := h.services[selfLink] if ok { h.Unlock() op.Fail(errors.New("host: service is already bound")) return } h.services[selfLink] = s h.Unlock() // Service is now attached to host; move to initialized state. if err := s.SetStage(StageInitialized); err != nil { op.Fail(err) return } // Start service asynchronously. go h.startService(op, s) }
func (s *ServiceContext) HandleRequest(ctx context.Context, op *operation.Operation) { switch op.GetRequest().Method { case "GET": if s.hGet != nil { s.hGet(ctx, op) return } case "POST": if s.hPost != nil { s.hPost(ctx, op) return } case "PATCH": if s.hPatch != nil { s.hPatch(ctx, op) return } case "PUT": if s.hPut != nil { s.hPut(ctx, op) return } case "DELETE": if s.hDelete != nil { s.hDelete(ctx, op) return } } op.Fail(errors.MethodNotAllowed{Allowed: s.allowedMethods()}) return }
func (f *FactoryServiceContext) HandleRequest(ctx context.Context, op *operation.Operation) { // TODO(PN): Support GET (need a way to get elements) and DELETE switch op.GetRequest().Method { case "POST": default: err := errors.MethodNotAllowed{Allowed: []string{"POST"}} op.Fail(err) return } f.handlePost(ctx, op) }
func (s *pingService) HandlePatch(ctx context.Context, op *operation.Operation) { req := &pingRequest{} err := op.DecodeBody(req) if err != nil { op.Fail(err) return } op.SetStatusCode(http.StatusCreated) op.Complete() // Ping specified URL pingOp := operation.NewPatch(ctx, req.URI, nil) pingOp.SetBody(req) client.Send(pingOp) }
func (s *ServiceContext) HandleStart(ctx context.Context, op *operation.Operation) { err := op.DecodeBody(s.h.GetState()) if err != nil && err != operation.ErrBodyNotSet { op.Fail(err) return } // Run the service handler's start handler if available if h, ok := s.h.(StartHandler); ok { err = op.CreateChild(ctx).Go(ctx, h.HandleStart).Wait() if err != nil { op.Fail(err) return } } op.Complete() }
// handlePost calls out to the factory service implementation's POST handler, // if it exists, and waits for completion. If this runs and completes without // error, the returned body is passed to the start operation for the service // created by this factory. func (f *FactoryServiceContext) handlePost(ctx context.Context, op *operation.Operation) { var err error var sd *common.ServiceDocument if h, ok := f.h.(PostHandler); ok { // Run the factory service's POST handler and wait for completion. err = op.CreateChild(ctx).Go(ctx, h.HandlePost).Wait() if err != nil { op.Fail(err) return } } doc := f.h.CreateDocument() err = op.DecodeBody(doc) if err != nil && err != io.EOF { op.Fail(err) return } sd = doc.GetServiceDocument() sd.SelfLink = path.Join(f.SelfLink(), uuid.New()) op.SetBody(doc) buf, err := op.EncodeBodyAsBuffer() if err != nil { op.Fail(err) return } // Start child service at service document's selflink startOp := op.NewPost(ctx, uri.Extend(uri.Local(), sd.SelfLink), buf) f.Host().StartService(startOp, f.h.CreateService()) err = startOp.Wait() if err != nil { op.Fail(err) return } op.Complete() }
// startService executes the necessary actions to move a service from // the available stage, to the started stage, to the available stage. func (h *ServiceHost) startService(op *operation.Operation, s Service) { ctx := context.Background() err := op.CreateChild(ctx).Go(ctx, s.HandleStart).Wait() if err != nil { op.Fail(err) return } if err := s.SetStage(StageStarted); err != nil { op.Fail(err) return } // Stuff may happen between the started and available stages. // This separation is kept here for parity with the Java XENON implementation. if err := s.SetStage(StageAvailable); err != nil { op.Fail(err) return } op.Complete() }
func (m *MinimalService) HandleRequest(ctx context.Context, op *operation.Operation) { op.Fail(errors.New("host: service not implemented")) }