VOL-1967 move api-server to separate repository

Current with voltha-go acf0adaf2d91ae72b55192cc8a939e0485918d16

Change-Id: I000ea6be0789e20c922bd671562b58a7120892ae
diff --git a/internal/pkg/afrouter/method-router.go b/internal/pkg/afrouter/method-router.go
new file mode 100644
index 0000000..2916edf
--- /dev/null
+++ b/internal/pkg/afrouter/method-router.go
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package afrouter
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/protobuf/proto"
+	"github.com/opencord/voltha-go/common/log"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/metadata"
+	"io/ioutil"
+)
+
+const NoMeta = "nometa"
+
+type MethodRouter struct {
+	name            string
+	service         string
+	methodRouter    map[string]map[string]Router // map of [metadata][method]
+	methodStreaming map[string]streamingDirections
+}
+
+type streamingDirections struct {
+	request  bool
+	response bool
+}
+
+func newMethodRouter(config *RouterConfig) (Router, error) {
+	// Load the protobuf descriptor file
+	fb, err := ioutil.ReadFile(config.ProtoFile)
+	if err != nil {
+		log.Errorf("Could not open proto file '%s'", config.ProtoFile)
+		return nil, err
+	}
+	if err := proto.Unmarshal(fb, &config.protoDescriptor); err != nil {
+		log.Errorf("Could not unmarshal %s, %v", "proto.pb", err)
+		return nil, err
+	}
+
+	mr := MethodRouter{
+		name:    config.Name,
+		service: config.ProtoService,
+		methodRouter: map[string]map[string]Router{
+			NoMeta: make(map[string]Router), // For routes not needing metadata (all except binding at this time)
+		},
+		methodStreaming: make(map[string]streamingDirections),
+	}
+	log.Debugf("Processing MethodRouter config %v", *config)
+
+	for _, file := range config.protoDescriptor.File {
+		if *file.Package == config.ProtoPackage {
+			for _, service := range file.Service {
+				if *service.Name == config.ProtoService {
+					for _, method := range service.Method {
+						if clientStreaming, serverStreaming := method.ClientStreaming != nil && *method.ClientStreaming, method.ServerStreaming != nil && *method.ServerStreaming; clientStreaming || serverStreaming {
+							mr.methodStreaming[*method.Name] = streamingDirections{
+								request:  clientStreaming,
+								response: serverStreaming,
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if len(config.Routes) == 0 {
+		return nil, errors.New(fmt.Sprintf("Router %s must have at least one route", config.Name))
+	}
+	for _, rtv := range config.Routes {
+		//log.Debugf("Processing route: %v",rtv)
+		var idx1 string
+		r, err := newSubRouter(config, &rtv)
+		if err != nil {
+			return nil, err
+		}
+		if rtv.Type == RouteTypeBinding {
+			idx1 = rtv.Binding.Field
+			if _, ok := mr.methodRouter[idx1]; !ok { // /First attempt on this key
+				mr.methodRouter[idx1] = make(map[string]Router)
+			}
+		} else {
+			idx1 = NoMeta
+		}
+		switch len(rtv.Methods) {
+		case 0:
+			return nil, errors.New(fmt.Sprintf("Route for router %s must have at least one method", config.Name))
+		case 1:
+			if rtv.Methods[0] == "*" {
+				return r, nil
+			} else {
+				log.Debugf("Setting router '%s' for single method '%s'", r.Name(), rtv.Methods[0])
+				if _, ok := mr.methodRouter[idx1][rtv.Methods[0]]; !ok {
+					mr.methodRouter[idx1][rtv.Methods[0]] = r
+				} else {
+					err := errors.New(fmt.Sprintf("Attempt to define method %s for 2 routes: %s & %s", rtv.Methods[0],
+						r.Name(), mr.methodRouter[idx1][rtv.Methods[0]].Name()))
+					log.Error(err)
+					return mr, err
+				}
+			}
+		default:
+			for _, m := range rtv.Methods {
+				log.Debugf("Processing Method %s", m)
+				if _, ok := mr.methodRouter[idx1][m]; !ok {
+					log.Debugf("Setting router '%s' for method '%s'", r.Name(), m)
+					mr.methodRouter[idx1][m] = r
+				} else {
+					err := errors.New(fmt.Sprintf("Attempt to define method %s for 2 routes: %s & %s", m, r.Name(), mr.methodRouter[idx1][m].Name()))
+					log.Error(err)
+					return mr, err
+				}
+			}
+		}
+	}
+
+	return mr, nil
+}
+
+func (mr MethodRouter) Name() string {
+	return mr.name
+}
+
+func (mr MethodRouter) Service() string {
+	return mr.service
+}
+
+func (mr MethodRouter) GetMetaKeyVal(serverStream grpc.ServerStream) (string, string, error) {
+	var rtrnK = NoMeta
+	var rtrnV = ""
+
+	// Get the metadata from the server stream
+	md, ok := metadata.FromIncomingContext(serverStream.Context())
+	if !ok {
+		return rtrnK, rtrnV, errors.New("Could not get a server stream metadata")
+	}
+
+	// Determine if one of the method routing keys exists in the metadata
+	for k := range mr.methodRouter {
+		if _, ok := md[k]; ok {
+			rtrnV = md[k][0]
+			rtrnK = k
+			break
+		}
+	}
+	return rtrnK, rtrnV, nil
+
+}
+
+func (mr MethodRouter) ReplyHandler(sel interface{}) error {
+	switch sl := sel.(type) {
+	case *responseFrame:
+		if r, ok := mr.methodRouter[NoMeta][sl.method]; ok {
+			return r.ReplyHandler(sel)
+		}
+		return errors.New("MethodRouter.ReplyHandler called with unknown meta or method")
+	default:
+		return errors.New("MethodRouter.ReplyHandler called with non-reponseFrame")
+	}
+}
+
+func (mr MethodRouter) Route(sel interface{}) (*backend, *connection) {
+	switch sl := sel.(type) {
+	case *requestFrame:
+		if r, ok := mr.methodRouter[sl.metaKey][sl.methodInfo.method]; ok {
+			return r.Route(sel)
+		}
+		sl.err = fmt.Errorf("MethodRouter.Route unable to resolve meta %s, method %s", sl.metaKey, sl.methodInfo.method)
+		log.Error(sl.err)
+		return nil, nil
+	default:
+		log.Errorf("Internal: invalid data type in Route call %v", sel)
+		return nil, nil
+	}
+}
+
+func (mr MethodRouter) IsStreaming(method string) (bool, bool) {
+	streamingDirections := mr.methodStreaming[method]
+	return streamingDirections.request, streamingDirections.response
+}
+
+func (mr MethodRouter) BackendCluster(mthd string, metaKey string) (*cluster, error) {
+	if r, ok := mr.methodRouter[metaKey][mthd]; ok {
+		return r.BackendCluster(mthd, metaKey)
+	}
+	err := errors.New(fmt.Sprintf("No backend cluster exists for method '%s' using meta key '%s'", mthd, metaKey))
+	log.Error(err)
+	return nil, err
+}
+
+func (mr MethodRouter) FindBackendCluster(beName string) *cluster {
+	for _, meta := range mr.methodRouter {
+		for _, r := range meta {
+			if rtrn := r.FindBackendCluster(beName); rtrn != nil {
+				return rtrn
+			}
+		}
+	}
+	return nil
+}