Example #1
0
func (g *jsonschema) generateEnumSchema(file *generator.FileDescriptor, enum *generator.EnumDescriptor, index int) {
	typeName := file.GetPackage() + "." + strings.Join(enum.TypeName(), ".")
	typeName = strings.TrimPrefix(typeName, ".")

	def := g.definitions[typeName]
	if def == nil {
		def = g.enumToSchema(file, enum)
		g.definitions[typeName] = def
	}
}
Example #2
0
func (g *jsonschema) generateMessageSchema(file *generator.FileDescriptor, msg *generator.Descriptor, index int) {
	typeName := file.GetPackage() + "." + strings.Join(msg.TypeName(), ".")
	typeName = strings.TrimPrefix(typeName, ".")

	if g.definitions[typeName] == nil {
		def, deps := g.messageToSchema(file, msg)
		g.definitions[typeName] = def
		g.dependencies[typeName] = deps
	}
}
Example #3
0
// Generate generates code for the services in the given file.
func (g *gensql) Generate(file *generator.FileDescriptor) {
	imp := generator.NewPluginImports(g.gen)
	g.imports = imp
	g.sqlPkg = imp.NewImport("database/sql")
	g.jsonPkg = imp.NewImport("encoding/json")
	g.contextPkg = imp.NewImport("golang.org/x/net/context")
	g.tracePkg = imp.NewImport("limbo.services/trace")
	g.runtimePkg = imp.NewImport("limbo.services/core/runtime/limbo")
	g.timePkg = imp.NewImport("time")
	g.mysqlPkg = imp.NewImport("github.com/go-sql-driver/mysql")

	var models []*generator.Descriptor

	for _, msg := range file.Messages() {
		model := limbo.GetModel(msg)
		if model == nil {
			continue
		}
		g.models["."+file.GetPackage()+"."+msg.GetName()] = msg
		models = append(models, msg)
	}

	if len(models) == 0 {
		return
	}

	// phase 1
	for _, msg := range models {
		g.populateMessage(file, msg)
	}

	// phase 2
	for _, msg := range models {
		g.populateMessageDeep(msg, nil)
	}

	for _, msg := range models {
		g.generateStmt(file, msg)
		g.generateScanners(file, msg)
	}

	// phase 3
	for _, msg := range models {
		model := limbo.GetModel(msg)
		model.DeepColumn = nil
		model.DeepJoin = nil
		model.DeepScanner = nil
	}

}
Example #4
0
func (g *jsonschema) enumToSchema(file *generator.FileDescriptor, desc *generator.EnumDescriptor) interface{} {
	typeName := file.GetPackage() + "." + strings.Join(desc.TypeName(), ".")
	typeName = strings.TrimPrefix(typeName, ".")

	title := desc.TypeName()[len(desc.TypeName())-1]

	values := make([]interface{}, 0, 2*len(desc.Value))
	for _, x := range desc.Value {
		values = append(values, x.GetNumber())
		values = append(values, x.GetName())
	}

	return map[string]interface{}{
		// "id":    typeName,
		"enum":  values,
		"title": title,
	}
}
Example #5
0
// Generate generates code for the services in the given file.
func (g *svcauth) Generate(file *generator.FileDescriptor) {
	for _, msg := range file.Messages() {
		name := file.GetPackage() + "." + msg.GetName()
		g.messages[name] = msg
	}

	if len(file.FileDescriptorProto.Service) == 0 {
		return
	}

	imp := generator.NewPluginImports(g.gen)
	g.imports = imp
	g.contextPkg = imp.NewImport("golang.org/x/net/context")
	g.runtimePkg = imp.NewImport("limbo.services/core/runtime/limbo")

	for i, service := range file.FileDescriptorProto.Service {
		g.generateService(file, service, i)
	}
}
Example #6
0
// generateService generates all the code for the named service.
func (g *grpc) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) {
	path := fmt.Sprintf("6,%d", index) // 6 means service.

	origServName := service.GetName()
	fullServName := origServName
	if pkg := file.GetPackage(); pkg != "" {
		fullServName = pkg + "." + fullServName
	}
	servName := generator.CamelCase(origServName)

	g.P()
	g.P("// Client API for ", servName, " service")
	g.P()

	// Client interface.
	g.P("type ", servName, "Client interface {")
	for i, method := range service.Method {
		g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service.
		g.P(g.generateClientSignature(servName, method))
	}
	g.P("}")
	g.P()

	// Client structure.
	g.P("type ", unexport(servName), "Client struct {")
	g.P("cc *", grpcPkg, ".ClientConn")
	g.P("}")
	g.P()

	// NewClient factory.
	g.P("func New", servName, "Client (cc *", grpcPkg, ".ClientConn) ", servName, "Client {")
	g.P("return &", unexport(servName), "Client{cc}")
	g.P("}")
	g.P()

	var methodIndex, streamIndex int
	serviceDescVar := "_" + servName + "_serviceDesc"
	// Client method implementations.
	for _, method := range service.Method {
		var descExpr string
		if !method.GetServerStreaming() && !method.GetClientStreaming() {
			// Unary RPC method
			descExpr = fmt.Sprintf("&%s.Methods[%d]", serviceDescVar, methodIndex)
			methodIndex++
		} else {
			// Streaming RPC method
			descExpr = fmt.Sprintf("&%s.Streams[%d]", serviceDescVar, streamIndex)
			streamIndex++
		}
		g.generateClientMethod(servName, fullServName, serviceDescVar, method, descExpr)
	}

	g.P("// Server API for ", servName, " service")
	g.P()

	// Server interface.
	serverType := servName + "Server"
	g.P("type ", serverType, " interface {")
	for i, method := range service.Method {
		g.gen.PrintComments(fmt.Sprintf("%s,2,%d", path, i)) // 2 means method in a service.
		g.P(g.generateServerSignature(servName, method))
	}
	g.P("}")
	g.P()

	// Server registration.
	g.P("func Register", servName, "Server(s *", grpcPkg, ".Server, srv ", serverType, ", options ...", gogogrpcPkg, ".ServerOption) {")
	g.P("s.RegisterService(", gogogrpcPkg, ".ApplyServerOptions(&", serviceDescVar, ", srv, options))")
	g.P("}")
	g.P()

	// Server handler implementations.
	var handlerNames []string
	for _, method := range service.Method {
		hname := g.generateServerMethod(servName, fullServName, method)
		handlerNames = append(handlerNames, hname)
	}

	// Service descriptor.
	g.P("var ", serviceDescVar, " = ", grpcPkg, ".ServiceDesc {")
	g.P("ServiceName: ", strconv.Quote(fullServName), ",")
	g.P("HandlerType: (*", serverType, ")(nil),")
	g.P("Methods: []", grpcPkg, ".MethodDesc{")
	for i, method := range service.Method {
		if method.GetServerStreaming() || method.GetClientStreaming() {
			continue
		}
		g.P("{")
		g.P("MethodName: ", strconv.Quote(method.GetName()), ",")
		g.P("Handler: ", handlerNames[i], ",")
		g.P("},")
	}
	g.P("},")
	g.P("Streams: []", grpcPkg, ".StreamDesc{")
	for i, method := range service.Method {
		if !method.GetServerStreaming() && !method.GetClientStreaming() {
			continue
		}
		g.P("{")
		g.P("StreamName: ", strconv.Quote(method.GetName()), ",")
		g.P("Handler: ", handlerNames[i], ",")
		if method.GetServerStreaming() {
			g.P("ServerStreams: true,")
		}
		if method.GetClientStreaming() {
			g.P("ClientStreams: true,")
		}
		g.P("},")
	}
	g.P("},")
	g.P("Metadata: ", file.VarName(), ",")
	g.P("}")
	g.P()
}
Example #7
0
func (g *gensql) populateMessage(file *generator.FileDescriptor, msg *generator.Descriptor) {
	model := limbo.GetModel(msg)
	model.MessageType = "." + file.GetPackage() + "." + msg.GetName()

	{ // default scanner
		var found bool
		for _, scanner := range model.Scanner {
			if scanner.Name == "" {
				found = true
				break
			}
		}
		if !found {
			model.Scanner = append(model.Scanner, &limbo.ScannerDescriptor{Fields: "*"})
		}
	}

	for _, scanner := range model.Scanner {
		scanner.MessageType = "." + file.GetPackage() + "." + msg.GetName()
	}

	for _, field := range msg.GetField() {
		if column := limbo.GetColumn(field); column != nil {
			column.MessageType = "." + file.GetPackage() + "." + msg.GetName()
			column.FieldName = field.GetName()
			if column.Name == "" {
				column.Name = field.GetName()
			}

			model.Column = append(model.Column, column)
		}

		if join := limbo.GetJoin(field); join != nil {
			if field.GetType() != pb.FieldDescriptorProto_TYPE_MESSAGE {
				g.gen.Fail(field.GetName(), "in", msg.GetName(), "must be a message")
			}

			join.MessageType = "." + file.GetPackage() + "." + msg.GetName()
			join.FieldName = field.GetName()
			join.ForeignMessageType = field.GetTypeName()

			if join.Name == "" {
				join.Name = field.GetName()
			}

			if join.Key == "" {
				join.Key = field.GetName() + "_id"
			}

			if join.ForeignKey == "" {
				join.ForeignKey = "id"
			}

			model.Join = append(model.Join, join)
		}
	}

	sort.Sort(limbo.SortedColumnDescriptors(model.Column))
	sort.Sort(limbo.SortedJoinDescriptors(model.Join))
	sort.Sort(limbo.SortedScannerDescriptors(model.Scanner))
}
Example #8
0
func (g *jsonschema) messageToSchema(file *generator.FileDescriptor, desc *generator.Descriptor) (interface{}, []string) {
	typeName := file.GetPackage() + "." + strings.Join(desc.TypeName(), ".")
	typeName = strings.TrimPrefix(typeName, ".")

	title := desc.TypeName()[len(desc.TypeName())-1]

	var (
		dependencies       []string
		properties         = make(map[string]interface{})
		requiredProperties []string
	)

	for i, field := range desc.GetField() {
		if field.OneofIndex != nil {
			continue
		}

		f, dep := g.fieldToSchema(field)
		if f == nil {
			continue
		}

		if limbo.IsRequiredProperty(field) {
			requiredProperties = append(requiredProperties, getJSONName(field))
		}

		{
			comment := g.gen.Comments(fmt.Sprintf("%s,%d,%d", desc.Path(), 2, i))
			comment = strings.TrimSpace(comment)
			if comment != "" {
				f["description"] = comment
			}
		}

		properties[getJSONName(field)] = f
		if dep != "" {
			dependencies = append(dependencies, dep)
		}
	}

	schema := map[string]interface{}{
		"type":       "object",
		"properties": properties,
	}
	if len(requiredProperties) > 0 {
		schema["required"] = requiredProperties
	}

	if len(desc.OneofDecl) > 0 {
		allOffDefs := make([]interface{}, 0, 1+len(desc.OneofDecl))
		oneOfDefs := make([][]interface{}, len(desc.OneofDecl))
		for i, field := range desc.GetField() {
			if field.OneofIndex == nil {
				continue
			}
			oneofIndex := *field.OneofIndex

			f, dep := g.fieldToSchema(field)
			if f == nil {
				continue
			}

			if field.IsRepeated() {
				f = map[string]interface{}{
					"type":  "array",
					"items": f,
				}
			}

			{
				comment := g.gen.Comments(fmt.Sprintf("%s,%d,%d", desc.Path(), 2, i))
				comment = strings.TrimSpace(comment)
				if comment != "" {
					f["description"] = comment
				}
			}

			def := map[string]interface{}{
				"type": "object",
				"properties": map[string]interface{}{
					getJSONName(field): f,
				},
				"required": []string{getJSONName(field)},
			}

			oneOfDefs[oneofIndex] = append(oneOfDefs[oneofIndex], def)
			if dep != "" {
				dependencies = append(dependencies, dep)
			}
		}

		allOffDefs = append(allOffDefs, schema)
		for i, defs := range oneOfDefs {
			def := map[string]interface{}{
				"oneOf": defs,
			}

			{
				comment := g.gen.Comments(fmt.Sprintf("%s,%d,%d", desc.Path(), 8, i))
				comment = strings.TrimSpace(comment)
				if comment != "" {
					def["description"] = comment
				}
			}

			allOffDefs = append(allOffDefs, def)
		}

		schema = map[string]interface{}{
			"type":  "object",
			"allOf": allOffDefs,
		}
	}

	{
		comment := g.gen.Comments(desc.Path())
		comment = strings.TrimSpace(comment)
		if comment != "" {
			schema["description"] = comment
		}
	}

	{
		schema["title"] = title
		// schema["id"] = typeName
	}

	{
		dependencies = uniqStrings(dependencies)
	}

	return schema, dependencies
}
Example #9
0
// generateService generates all the code for the named service.
func (g *svcauth) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) {
	methods := g.findMethods(file, service)
	if len(methods) == 0 {
		return
	}

	origServName := service.GetName()
	fullServName := file.GetPackage() + "." + origServName
	servName := generator.CamelCase(origServName)
	authDescVarName := "_" + servName + "_authDesc"

	methodsByName := make(map[*pb.MethodDescriptorProto]*authMethod)
	for _, m := range methods {
		methodsByName[m.method] = m
	}

	g.gen.AddInitf("%s.RegisterServiceAuthDesc(&%s)", g.runtimePkg.Use(), authDescVarName)

	var interfaceMethods []string

	g.P(`var `, authDescVarName, ` = `, g.runtimePkg.Use(), `.ServiceAuthDesc{`)
	g.P(`ServiceName: `, strconv.Quote(fullServName), `,`)
	g.P(`HandlerType: ((*`, servName, `Server)(nil)),`)
	g.P(`AuthHandlerType: ((*`, servName, `ServerAuth)(nil)),`)
	g.P(`Methods: []`, g.runtimePkg.Use(), `.MethodAuthDesc{`)
	for _, method := range service.Method {
		if method.GetServerStreaming() || method.GetClientStreaming() {
			continue
		}
		g.P(`{`)
		g.P(`MethodName: `, strconv.Quote(method.GetName()), `,`)
		g.generateDesc(servName, method, methodsByName[method], &interfaceMethods)
		g.P("},")
	}
	g.P("},")
	g.P(`Streams: []`, g.runtimePkg.Use(), `.StreamAuthDesc{`)
	for _, method := range service.Method {
		if !method.GetServerStreaming() && !method.GetClientStreaming() {
			continue
		}
		g.P(`{`)
		g.P(`StreamName: `, strconv.Quote(method.GetName()), `,`)
		g.generateDesc(servName, method, methodsByName[method], &interfaceMethods)
		g.P("},")
	}
	g.P("},")
	g.P("}")
	g.P()

	if len(interfaceMethods) > 0 {
		sort.Strings(interfaceMethods)
		last := ""
		g.P(`type `, servName, `ServerAuth interface {`)
		for _, sig := range interfaceMethods {
			if sig != last {
				last = sig
				g.P(sig)
			}
		}
		g.P(`}`)
	}
}
Example #10
0
func (g *svcauth) findMethods(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto) []*authMethod {
	methods := make([]*authMethod, 0, len(service.Method))

	var (
		defaultAuthnInfo *AuthnRule
		defaultAuthzInfo *AuthzRule
	)

	if service.Options != nil {
		v, _ := proto.GetExtension(service.Options, E_DefaultAuthn)
		defaultAuthnInfo, _ = v.(*AuthnRule)
	}

	if service.Options != nil {
		v, _ := proto.GetExtension(service.Options, E_DefaultAuthz)
		defaultAuthzInfo, _ = v.(*AuthzRule)
	}

	for _, method := range service.Method {
		var (
			authnInfo *AuthnRule
			authzInfo *AuthzRule
		)

		{ // authn
			v, _ := proto.GetExtension(method.Options, E_Authn)
			authnInfo, _ = v.(*AuthnRule)
			if authnInfo == nil && defaultAuthnInfo != nil {
				authnInfo = &AuthnRule{}
			}
			if authnInfo != nil {
				authnInfo = defaultAuthnInfo.Inherit(authnInfo)
				authnInfo.SetDefaults()
			}
		}

		{ // authz
			v, _ := proto.GetExtension(method.Options, E_Authz)
			authzInfo, _ = v.(*AuthzRule)
			if authzInfo == nil && defaultAuthzInfo != nil {
				authzInfo = &AuthzRule{}
			}
			if authzInfo != nil {
				authzInfo = defaultAuthzInfo.Inherit(authzInfo)
				authzInfo.SetDefaults()
			}
		}

		if authnInfo == nil && authzInfo == nil {
			continue
		}

		methods = append(methods, &authMethod{
			file:    file,
			service: service,
			method:  method,
			Authn:   authnInfo,
			Authz:   authzInfo,
			Name:    fmt.Sprintf("/%s.%s/%s", file.GetPackage(), service.GetName(), method.GetName()),
		})
	}

	return methods
}
Example #11
0
// generateService generates all the code for the named service.
func (g *svchttp) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) {
	apis := filterAPIs(service, service.Method, index)
	if len(apis) == 0 {
		return
	}

	origServName := service.GetName()
	fullServName := file.GetPackage() + "." + origServName
	servName := generator.CamelCase(origServName)
	gatewayVarName := "_" + servName + "_gatewayDesc"

	g.gen.AddInitf("%s.RegisterGatewayDesc(&%s)", g.runtimePkg.Use(), gatewayVarName)

	g.P(`var `, gatewayVarName, ` = `, g.runtimePkg.Use(), `.GatewayDesc{`)
	g.P(`ServiceName: `, strconv.Quote(fullServName), `,`)
	g.P(`HandlerType: ((*`, servName, `Server)(nil)),`)
	g.P(`Routes: []`, g.runtimePkg.Use(), `.RouteDesc{`)
	for _, api := range apis {
		_, method := api.desc, api.method

		httpMethod, pattern, ok := api.GetMethodAndPattern()
		if !ok {
			g.gen.Fail("xyz.featherhead.http requires a method: pattern")
		}

		if idx := strings.IndexRune(pattern, '?'); idx >= 0 {
			pattern = pattern[:idx]
		}

		g.P(`{`)
		g.P(`Method: `, strconv.Quote(httpMethod), `,`)
		g.P(`Pattern: `, strconv.Quote(pattern), `,`)
		g.P(`Handler: `, g.generateServerCallName(servName, method), `,`)
		g.P("},")
	}
	g.P("},")
	g.P("}")
	g.P()

	// Server handler implementations.
	for _, api := range apis {
		info, method := api.desc, api.method

		inputTypeName := method.GetInputType()
		inputType, _ := g.gen.ObjectNamed(inputTypeName).(*generator.Descriptor)

		httpMethod, pattern, ok := api.GetMethodAndPattern()
		queryParams := map[string]string{}
		if !ok {
			g.gen.Fail("xyz.featherhead.http requires a method: pattern")
		}

		if idx := strings.IndexRune(pattern, '?'); idx >= 0 {
			queryString := pattern[idx+1:]
			pattern = pattern[:idx]

			for _, pair := range strings.SplitN(queryString, "&", -1) {
				idx := strings.Index(pair, "={")
				if pair[len(pair)-1] != '}' || idx < 0 {
					g.gen.Fail("invalid query paramter")
				}
				queryParams[pair[:idx]] = pair[idx+2 : len(pair)-1]
			}
		}

		vars, err := router.ExtractVariables(pattern)
		if err != nil {
			g.gen.Error(err)
			return
		}

		var (
			httpResponseWriter = g.httpPkg.Use() + ".ResponseWriter"
			httpRequest        = g.httpPkg.Use() + ".Request"
			contextContext     = g.contextPkg.Use() + ".Context"
		)

		handlerMethod := g.generateServerCallName(servName, method)
		jujuErrors := g.jujuErrorsPkg.Use()
		g.P("func ", handlerMethod, "(srvDesc *", g.grpcPkg.Use(), ".ServiceDesc, srv interface{}, ctx ", contextContext, ", rw ", httpResponseWriter, ", req *", httpRequest, ") error {")
		g.P("if req.Method != ", strconv.Quote(httpMethod), "{")
		g.P(`  return `, jujuErrors, `.MethodNotAllowedf("expected `, httpMethod, ` request")`)
		g.P("}")
		g.P()

		if len(vars) > 0 {
			routerP := g.routerPkg.Use() + ".P"
			g.P(`params := `, routerP, `(ctx)`)
		}

		g.P(`stream, err := `, g.runtimePkg.Use(), `.NewServerStream(ctx, rw, req, `,
			method.GetServerStreaming(), `, `, method.GetClientStreaming(), `, `, int(info.PageSize), `, func(x interface{}) error {`)
		g.P(`input := x.(*`, g.typeName(inputTypeName), `)`)
		g.P(`_ = input`)
		g.P()

		for param, value := range queryParams {
			g.P("// populate ?", param, "=", value)
			g.generateHttpMapping(inputType, value, "req.URL.Query().Get("+strconv.Quote(param)+")")
		}

		for _, v := range vars {
			g.P("// populate {", v.Name, "}")
			g.generateHttpMapping(inputType, v.Name, "params.Get("+strconv.Quote(v.Name)+")")
		}

		g.P(`return nil`)
		g.P(`})`)
		g.P()

		if !api.stream {
			g.P(`desc := &srvDesc.Methods[`, api.index, `]`)
			g.P(`output, err := desc.Handler(srv, stream.Context(), stream.RecvMsg, nil)`)
			g.P(`if err == nil && output == nil {`)
			g.P(`err = `, g.grpcPkg.Use(), `.Errorf(`, g.grpcCodesPkg.Use(), `.Internal, "internal server error")`)
			g.P(`}`)
			g.P(`if err == nil {`)
			g.P(`err = stream.SendMsg(output)`)
			g.P(`}`)
		} else {
			g.P(`desc := &srvDesc.Streams[`, api.index, `]`)
			g.P(`err = desc.Handler(srv, stream)`)
		}
		g.P(`if err != nil {`)
		g.P(`stream.SetError(err)`)
		g.P(`}`)
		g.P()

		g.P(`return stream.CloseSend()`)
		g.P("}")
		g.P()

	}

}