service

package
v0.0.0-...-e65cc6c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2019 License: Apache-2.0 Imports: 18 Imported by: 7

Documentation

Index

Examples

Constants

View Source
const (
	AlreadyRegistered    = `WF_ALREADY_REGISTERED`
	ApiTypeNotRegistered = `WF_API_TYPE_NOT_REGISTERED`
	IllegalTypeName      = `WF_ILLEGAL_TYPE_NAME`
	NoCommonNamespace    = `WF_NO_COMMON_NAMESPACE`
	NoSuchApi            = `WF_NO_SUCH_API`
	NoSuchMethod         = `WF_NO_SUCH_METHOD`
	NoSuchState          = `WF_NO_SUCH_STATE`
	NotFound             = `WF_NOT_FOUND`
	NotFunc              = `WF_NOT_FUNC`
	NotPuppetObject      = `WF_NOT_PUPPET_OBJECT`
	NoStateConverter     = `WF_NO_STATE_CONVERTER`
	TypeNameClash        = `WF_TYPE_NAME_CLASH`
)

Variables

View Source
var ErrorMetaType px.ObjectType
View Source
var ParameterMetaType px.ObjectType
View Source
var ServerVersion = semver.MustParseVersion(`0.1.0`)

Functions

func CreateTypeSet

func CreateTypeSet(ts map[string]px.Type) px.TypeSet

func FederatedLoader

func FederatedLoader(parentLoader px.Loader) px.Loader

New creates a new federated loader instance

func NewSubService

func NewSubService(def serviceapi.Definition) serviceapi.Service

Types

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

func NewServiceBuilder

func NewServiceBuilder(ctx px.Context, serviceName string) *Builder

func (*Builder) BuildResource

func (ds *Builder) BuildResource(goType interface{}, bld func(f ResourceTypeBuilder)) px.AnnotatedType

func (*Builder) RegisterAPI

func (ds *Builder) RegisterAPI(name string, callable interface{})

RegisterAPI registers a struct as an invokable. The callable instance given as the argument becomes the actual receiver the calls.

func (*Builder) RegisterApiType

func (ds *Builder) RegisterApiType(name string, callable interface{})

RegisterAPIType registers a the type of a struct as an invokable type. The struct should be a zero value. This method must be used to ensure that all type info is present for callable instances added to an already created service

func (*Builder) RegisterHandler

func (ds *Builder) RegisterHandler(name string, callable interface{}, stateType px.Type)

RegisterHandler registers a callable struct as an invokable capable of handling a state described using px.Type. The callable instance given as the argument becomes the actual receiver the calls.

func (*Builder) RegisterState

func (ds *Builder) RegisterState(name string, state wf.State)

RegisterState registers the unresolved state of a resource.

func (*Builder) RegisterStateConverter

func (ds *Builder) RegisterStateConverter(sf wf.StateConverter)

func (*Builder) RegisterStep

func (ds *Builder) RegisterStep(step wf.Step)

RegisterStep registers an step

func (*Builder) RegisterType

func (ds *Builder) RegisterType(typ px.Type)

func (*Builder) RegisterTypes

func (ds *Builder) RegisterTypes(namespace string, values ...interface{}) []px.Type

RegisterTypes registers arbitrary Go types to the TypeSet exported by this service.

A value is typically a pointer to the zero value of a struct. The name of the generated type for that struct will be the struct name prefixed by the service ID.

Example (AnnotatedTypeSet)
package main

import (
	"bytes"
	"fmt"
	"os"

	"github.com/lyraproj/pcore/pcore"
	"github.com/lyraproj/pcore/px"
	"github.com/lyraproj/pcore/serialization"
	"github.com/lyraproj/pcore/types"
	"github.com/lyraproj/servicesdk/annotation"
	"github.com/lyraproj/servicesdk/service"
)

type OwnerRes struct {
	Id    *string
	Phone string
}

type ContainedRes struct {
	Id      *string
	OwnerId string
	Stuff   string
}

func main() {
	pcore.Do(func(c px.Context) {
		sb := service.NewServiceBuilder(c, `My::Service`)

		sb.RegisterTypes("My",
			sb.BuildResource(&OwnerRes{}, func(rtb service.ResourceTypeBuilder) {
				rtb.ProvidedAttributes(`id`)
				rtb.ImmutableAttributes(`telephoneNumber`)
				rtb.Tags(map[string]string{`Phone`: `name=>telephoneNumber`})
				rtb.AddRelationship(`mine`, `My::ContainedRes`, annotation.KindContained, annotation.CardinalityMany, ``,
					[]string{`id`, `ownerId`})
			}),
			sb.BuildResource(&ContainedRes{}, func(rtb service.ResourceTypeBuilder) {
				rtb.ProvidedAttributes(`id`)
				rtb.AddRelationship(`owner`, `My::OwnerRes`, annotation.KindContainer, annotation.CardinalityOne, ``,
					[]string{`ownerId`, `id`})
			}),
		)
		s := sb.Server()
		ts, md := s.Metadata(c)
		bld := bytes.NewBufferString(``)
		coll := serialization.NewJsonStreamer(bld)

		sr := serialization.NewSerializer(pcore.RootContext(), px.EmptyMap)
		sr.Convert(types.WrapValues([]px.Value{ts, px.Wrap(c, md)}), coll)

		dr := serialization.NewDeserializer(c, px.EmptyMap)
		serialization.JsonToData(`/tmp/tst`, bld, dr)
		dt := dr.Value().(*types.Array)
		dt.At(0).ToString(os.Stdout, px.PrettyExpanded, nil)
		fmt.Println()
	})

}
Output:

TypeSet[{
  pcore_uri => 'http://puppet.com/2016.1/pcore',
  pcore_version => '1.0.0',
  name_authority => 'http://puppet.com/2016.1/runtime',
  name => 'My',
  version => '0.1.0',
  types => {
    ContainedRes => {
      annotations => {
        Lyra::Resource => {
          'providedAttributes' => ['id'],
          'relationships' => {
            'owner' => {
              'type' => OwnerRes,
              'kind' => 'container',
              'cardinality' => 'one',
              'keys' => ['ownerId', 'id']
            }
          }
        }
      },
      attributes => {
        'id' => Optional[String],
        'ownerId' => String,
        'stuff' => String
      }
    },
    OwnerRes => {
      annotations => {
        Lyra::Resource => {
          'immutableAttributes' => ['telephoneNumber'],
          'providedAttributes' => ['id'],
          'relationships' => {
            'mine' => {
              'type' => ContainedRes,
              'kind' => 'contained',
              'cardinality' => 'many',
              'keys' => ['id', 'ownerId']
            }
          }
        }
      },
      attributes => {
        'id' => Optional[String],
        'telephoneNumber' => String
      }
    }
  }
}]
Example (NestedType)
package main

import (
	"fmt"
	"os"

	"github.com/lyraproj/pcore/pcore"
	"github.com/lyraproj/pcore/px"
	"github.com/lyraproj/servicesdk/service"
)

type MyRes struct {
	Name  string
	Phone string
}

type MyOuterRes struct {
	Who  *MyRes
	What string
}

func main() {
	pcore.Do(func(c px.Context) {
		sb := service.NewServiceBuilder(c, `My::Service`)

		sb.RegisterTypes("My", &MyOuterRes{})

		s := sb.Server()
		ts, _ := s.Metadata(c)
		ts.ToString(os.Stdout, px.PrettyExpanded, nil)
		fmt.Println()
	})

}
Output:

TypeSet[{
  pcore_uri => 'http://puppet.com/2016.1/pcore',
  pcore_version => '1.0.0',
  name_authority => 'http://puppet.com/2016.1/runtime',
  name => 'My',
  version => '0.1.0',
  types => {
    MyOuterRes => {
      attributes => {
        'who' => Optional[MyRes],
        'what' => String
      }
    },
    MyRes => {
      attributes => {
        'name' => String,
        'phone' => String
      }
    }
  }
}]
Example (RecursiveType)
package main

import (
	"fmt"
	"os"
	"time"

	"github.com/lyraproj/pcore/pcore"
	"github.com/lyraproj/pcore/px"
	"github.com/lyraproj/servicesdk/service"
)

type MyRes struct {
	Name  string
	Phone string
}

type Person struct {
	Who      *MyRes
	Children []*Person
	Born     time.Time
}

func main() {
	pcore.Do(func(c px.Context) {
		sb := service.NewServiceBuilder(c, `My::Service`)

		sb.RegisterTypes("My", &Person{})

		s := sb.Server()
		ts, _ := s.Metadata(c)
		ts.ToString(os.Stdout, px.PrettyExpanded, nil)
		fmt.Println()
	})

}
Output:

TypeSet[{
  pcore_uri => 'http://puppet.com/2016.1/pcore',
  pcore_version => '1.0.0',
  name_authority => 'http://puppet.com/2016.1/runtime',
  name => 'My',
  version => '0.1.0',
  types => {
    MyRes => {
      attributes => {
        'name' => String,
        'phone' => String
      }
    },
    Person => {
      attributes => {
        'who' => Optional[MyRes],
        'children' => Array[Optional[Person]],
        'born' => Timestamp
      }
    }
  }
}]

func (*Builder) Server

func (ds *Builder) Server() *Server

type ResourceTypeBuilder

type ResourceTypeBuilder interface {
	AddRelationship(name, to, kind, cardinality, reverseName string, keys []string)
	ImmutableAttributes(names ...string)
	ProvidedAttributes(names ...string)
	Tags(tags map[string]string)
	Build(goType interface{}) px.AnnotatedType
}

type Server

type Server struct {
	// contains filtered or unexported fields
}

func (*Server) AddApi

func (s *Server) AddApi(name string, callable interface{}) serviceapi.Definition

func (*Server) Identifier

func (s *Server) Identifier(px.Context) px.TypedName

func (*Server) Invoke

func (s *Server) Invoke(c px.Context, api, name string, arguments ...px.Value) (result px.Value)
Example
package main

import (
	"fmt"

	"github.com/lyraproj/pcore/pcore"
	"github.com/lyraproj/pcore/px"
	"github.com/lyraproj/servicesdk/service"
)

type testAPI struct{}

func (*testAPI) First() string {
	return `first`
}

func (*testAPI) Second(suffix string) string {
	return `second ` + suffix
}

func main() {
	pcore.Do(func(c px.Context) {
		api := `My::TheApi`
		sb := service.NewServiceBuilder(c, `My::Service`)

		sb.RegisterAPI(api, &testAPI{})

		s := sb.Server()
		fmt.Println(s.Invoke(c, api, `first`))
		fmt.Println(s.Invoke(c, api, `second`, px.Wrap(c, `place`)))
	})

}
Output:

first
second place

func (*Server) Metadata

func (s *Server) Metadata(px.Context) (typeSet px.TypeSet, definitions []serviceapi.Definition)
Example (Api)
package main

import (
	"fmt"
	"os"

	"github.com/lyraproj/pcore/pcore"
	"github.com/lyraproj/pcore/px"
	"github.com/lyraproj/servicesdk/service"
	"github.com/lyraproj/servicesdk/wf"
)

type MyIdentityService struct {
	extToId map[string]px.URI
	idToExt map[px.URI]string
}

func (is *MyIdentityService) GetExternal(id px.URI) (string, error) {
	if ext, ok := is.idToExt[id]; ok {
		return ext, nil
	}
	return ``, wf.NotFound
}

func (is *MyIdentityService) GetInternal(ext string) (px.URI, error) {
	if id, ok := is.extToId[ext]; ok {
		return id, nil
	}
	return px.URI(``), wf.NotFound
}

func main() {
	pcore.Do(func(c px.Context) {
		sb := service.NewServiceBuilder(c, `My::Service`)

		sb.RegisterAPI(`My::Identity`, &MyIdentityService{map[string]px.URI{}, map[px.URI]string{}})

		s := sb.Server()
		ts, defs := s.Metadata(c)
		ts.ToString(os.Stdout, px.PrettyExpanded, nil)
		fmt.Println()
		for _, def := range defs {
			fmt.Println(px.ToPrettyString(def))
		}
	})

}
Output:

TypeSet[{
  pcore_uri => 'http://puppet.com/2016.1/pcore',
  pcore_version => '1.0.0',
  name_authority => 'http://puppet.com/2016.1/runtime',
  name => 'My',
  version => '0.1.0',
  types => {
    Identity => {
      functions => {
        'getExternal' => Callable[
          [String],
          String],
        'getInternal' => Callable[
          [String],
          String]
      }
    }
  }
}]
Service::Definition(
  'identifier' => TypedName(
    'namespace' => 'definition',
    'name' => 'My::Identity'
  ),
  'serviceId' => TypedName(
    'namespace' => 'service',
    'name' => 'My::Service'
  ),
  'properties' => {
    'interface' => My::Identity,
    'style' => 'callable'
  }
)
Example (Definitions)
package main

import (
	"fmt"

	"github.com/lyraproj/issue/issue"

	"github.com/lyraproj/servicesdk/lang/go/lyra"

	"github.com/lyraproj/pcore/pcore"
	"github.com/lyraproj/pcore/px"
	"github.com/lyraproj/servicesdk/service"
)

type MyRes struct {
	Name  string
	Phone string
}

func main() {
	pcore.Do(func(c px.Context) {
		sb := service.NewServiceBuilder(c, `My::Service`)

		sb.RegisterTypes("My", &MyRes{})
		sb.RegisterStep((&lyra.Workflow{
			Steps: map[string]lyra.Step{
				`X`: &lyra.Resource{
					State: func(struct {
						A string
						B string  `lookup:"foo"`
						C int     `puppet:"value=>23"`
						D *string `puppet:"value=>undef"`
						E *string
						F *string `value:"77"`
					}) *MyRes {
						return &MyRes{Name: `Bob`, Phone: `12345`}
					}},
				`Y`: &lyra.Call{
					Parameters: struct {
						P string `lookup:"foo" alias:"B"`
					}{},
					StepName: `z`,
				}}}).Resolve(c, `My::Test`, issue.ParseLocation(`(file: /test/x.go)`)))

		s := sb.Server()
		_, defs := s.Metadata(c)
		for _, def := range defs {
			fmt.Println(px.ToPrettyString(def))
		}
	})

}
Output:

Service::Definition(
  'identifier' => TypedName(
    'namespace' => 'definition',
    'name' => 'My::Test'
  ),
  'serviceId' => TypedName(
    'namespace' => 'service',
    'name' => 'My::Service'
  ),
  'properties' => {
    'steps' => [
      Service::Definition(
        'identifier' => TypedName(
          'namespace' => 'definition',
          'name' => 'My::Test::X'
        ),
        'serviceId' => TypedName(
          'namespace' => 'service',
          'name' => 'My::Service'
        ),
        'properties' => {
          'parameters' => [
            Lyra::Parameter(
              'name' => 'a',
              'type' => String
            ),
            Lyra::Parameter(
              'name' => 'b',
              'type' => String,
              'value' => Deferred(
                'name' => 'lookup',
                'arguments' => ['foo']
              )
            ),
            Lyra::Parameter(
              'name' => 'c',
              'type' => Integer,
              'value' => 23
            ),
            Lyra::Parameter(
              'name' => 'd',
              'type' => Optional[String]
            ),
            Lyra::Parameter(
              'name' => 'e',
              'type' => Optional[String]
            ),
            Lyra::Parameter(
              'name' => 'f',
              'type' => Optional[String],
              'value' => '77'
            )],
          'resourceType' => My::MyRes,
          'style' => 'resource',
          'origin' => '(file: /test/x.go)'
        }
      ),
      Service::Definition(
        'identifier' => TypedName(
          'namespace' => 'definition',
          'name' => 'My::Test::Y'
        ),
        'serviceId' => TypedName(
          'namespace' => 'service',
          'name' => 'My::Service'
        ),
        'properties' => {
          'parameters' => [
            Lyra::Parameter(
              'name' => 'p',
              'type' => String,
              'alias' => 'b',
              'value' => Deferred(
                'name' => 'lookup',
                'arguments' => ['foo']
              )
            )],
          'call' => 'z',
          'style' => 'call',
          'origin' => '(file: /test/x.go)'
        }
      )],
    'style' => 'workflow',
    'origin' => '(file: /test/x.go)'
  }
)
Example (State)
package main

import (
	"fmt"

	"github.com/lyraproj/issue/issue"

	"github.com/lyraproj/servicesdk/lang/go/lyra"

	"github.com/lyraproj/pcore/pcore"
	"github.com/lyraproj/pcore/px"
	"github.com/lyraproj/servicesdk/service"
)

type MyRes struct {
	Name  string
	Phone string
}

func main() {
	pcore.Do(func(c px.Context) {
		sb := service.NewServiceBuilder(c, `My::Service`)

		sb.RegisterTypes("My", &MyRes{})
		sb.RegisterStateConverter(lyra.StateConverter)
		sb.RegisterStep((&lyra.Workflow{
			Steps: map[string]lyra.Step{
				`X`: &lyra.Resource{
					State: func(parameters struct {
						A string
						B string
					}) *MyRes {
						return &MyRes{Name: `Bob`, Phone: `12345`}
					}}}}).Resolve(c, `My::Test`, issue.ParseLocation(`(file: /test/x.go)`)))

		s := sb.Server()
		fmt.Println(px.ToPrettyString(s.State(c, `My::Test::X`, px.EmptyMap)))
	})

}
Output:

My::MyRes(
  'name' => 'Bob',
  'phone' => '12345'
)
Example (TypeSet)
package main

import (
	"fmt"
	"os"

	"github.com/lyraproj/pcore/pcore"
	"github.com/lyraproj/pcore/px"
	"github.com/lyraproj/servicesdk/service"
)

type testAPI struct{}

func (*testAPI) First() string {
	return `first`
}

func (*testAPI) Second(suffix string) string {
	return `second ` + suffix
}

type MyRes struct {
	Name  string
	Phone string
}

func main() {
	pcore.Do(func(c px.Context) {
		sb := service.NewServiceBuilder(c, `My::Service`)

		sb.RegisterAPI(`My::TheApi`, &testAPI{})
		sb.RegisterTypes("My", &MyRes{})

		s := sb.Server()
		ts, _ := s.Metadata(c)
		ts.ToString(os.Stdout, px.PrettyExpanded, nil)
		fmt.Println()
	})

}
Output:

TypeSet[{
  pcore_uri => 'http://puppet.com/2016.1/pcore',
  pcore_version => '1.0.0',
  name_authority => 'http://puppet.com/2016.1/runtime',
  name => 'My',
  version => '0.1.0',
  types => {
    MyRes => {
      attributes => {
        'name' => String,
        'phone' => String
      }
    },
    TheApi => {
      functions => {
        'first' => Callable[
          [0, 0],
          String],
        'second' => Callable[
          [String],
          String]
      }
    }
  }
}]

func (*Server) State

func (s *Server) State(c px.Context, name string, parameters px.OrderedMap) px.PuppetObject

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL