func (fp *Proxy) findWorkflowFiles(ctx context.Context, flr *fission.FunctionLoadRequest) ([]string, error) {
	fi, err := os.Stat(flr.FilePath)
	if err != nil {
		return nil, fmt.Errorf("no file present at '%v", flr.FilePath)
	}
	if fi.IsDir() {
		contents, err := ioutil.ReadDir(flr.FilePath)
		if err != nil {
			return nil, fmt.Errorf("failed to read package: '%v", flr.FilePath)
		}
		if len(contents) == 0 {
			return nil, fmt.Errorf("package is empty")
		}
		var paths []string
		for _, n := range contents {
			file := path.Join(flr.FilePath, n.Name())
			paths = append(paths, file)
		}
		return paths, nil
	}
	return []string{flr.FilePath}, nil
}
findWorkflowFiles searches for all of the workflow definitions in a Fission package
package fission
import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path"
	"strings"
	"time"
	"github.com/fission/fission"
	"github.com/fission/fission-workflows/pkg/apiserver"
	"github.com/fission/fission-workflows/pkg/types"
	"github.com/fission/fission-workflows/pkg/types/typedvalues"
	"github.com/fission/fission-workflows/pkg/types/typedvalues/httpconv"
	"github.com/fission/fission-workflows/pkg/util"
	"github.com/fission/fission/router"
	"github.com/golang/protobuf/jsonpb"
	"github.com/hashicorp/golang-lru"
	"github.com/opentracing/opentracing-go"
	"github.com/sirupsen/logrus"
)
const fissionIDsCacheSize = 1E4
type Proxy struct {
	client         *apiserver.Client
	fissionIds     *lru.Cache  
	defaultTimeout time.Duration
}
func NewEnvironmentProxyServer(client *apiserver.Client, defaultTimeout time.Duration) *Proxy {
	cache, err := lru.New(fissionIDsCacheSize)
	if err != nil {
		panic(err)
	}
	if defaultTimeout <= 0 {
		panic("default timeout for the Fission Proxy must be larger than 0")
	}
	return &Proxy{
		client:         client,
		fissionIds:     cache,
		defaultTimeout: defaultTimeout,
	}
}
func (fp *Proxy) RegisterServer(mux *http.ServeMux) {
	mux.HandleFunc("/", fp.handleRequest)
	mux.HandleFunc("/v2/specialize", fp.handleSpecialize)
	mux.HandleFunc("/healthz", fp.handleHealthCheck)
}
func (fp *Proxy) handleHealthCheck(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
}
func (fp *Proxy) handleRequest(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	spanCtx, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders,
		opentracing.HTTPHeadersCarrier(r.Header))
	if err != nil && err != opentracing.ErrSpanContextNotFound {
		logrus.Warnf("Failed to extract tracer from proxy requrest: %v", err)
	}
	var opts []opentracing.StartSpanOption
	if spanCtx != nil {
		opts = append(opts, opentracing.ChildOf(spanCtx))
	}
	span := opentracing.StartSpan("fnenv/fission/envproxy.handleRequest", opts...)
	defer span.Finish()
	meta := router.HeadersToMetadata(router.HEADERS_FISSION_FUNCTION_PREFIX, r.Header)
	fnID := string(meta.UID)
	if len(meta.UID) == 0 {
		logrus.WithField("meta", meta).Error("Fission function name is missing")
		http.Error(w, "Fission function name is missing", 400)
		return
	}
	_, ok := fp.fissionIds.Get(fnID)
	if !ok {
		if fp.hasWorkflow(ctx, fnID) {
			logrus.WithField("fnID", fnID).Error("Unknown fission function name")
			http.Error(w, "Unknown fission function name; not specialized", 400)
			return
		}
		fp.fissionIds.Add(fnID, true)
	}
	inputs, err := httpconv.ParseRequest(r)
	if err != nil {
		logrus.Errorf("Failed to parse inputs: %v", err)
		http.Error(w, "Failed to parse inputs", 400)
		return
	}
	deadline := fp.determineDeadline(r)
	wfSpec := types.NewWorkflowInvocationSpec(fnID, deadline)
	wfSpec.Inputs = inputs
	if logrus.GetLevel() == logrus.DebugLevel {
		inputs, err := typedvalues.UnwrapMapTypedValue(wfSpec.Inputs)
		util.LogIfError(err)
		logrus.Debugf("Fission proxy request: %v - %v", wfSpec.WorkflowId, inputs)
	}
	if len(r.Header.Get("X-Async")) > 0 {
		invocationID, invokeErr := fp.client.Invocation.Invoke(ctx, wfSpec)
		if invokeErr != nil {
			logrus.Errorf("Failed to invoke: %v", invokeErr)
			http.Error(w, invokeErr.Error(), 500)
			return
		}
		w.WriteHeader(200)
		w.Write([]byte(invocationID.Id))
		return
	}
	wi, err := fp.client.Invocation.InvokeSync(ctx, wfSpec)
	if err != nil {
		logrus.Errorf("Failed to invoke: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if !wi.Status.Successful() && wi.Status.Error == nil {
		logrus.Warn("Failed invocation does not contain error")
		wi.Status.Error = &types.Error{
			Message: "Unknown error",
		}
	}
	httpconv.FormatResponse(w, wi.Status.Output, wi.Status.OutputHeaders, wi.Status.Error)
	if !wi.Status.Successful() {
		logrus.Errorf("Invocation not successful, was '%v': %v", wi.Status.Status.String(), wi.Status.Error.Error())
	} else if wi.Status.Output == nil {
		logrus.Debugf("Invocation '%v' has no output.", fnID)
	} else {
		logrus.Debugf("Response Content-Type: %v", w.Header().Get("Content-Type"))
	}
}
func (fp *Proxy) handleSpecialize(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logrus.Info("Specializing...")
	bs, err := ioutil.ReadAll(r.Body)
	if err != nil {
		logrus.Errorf("Failed to read body: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("failed to read body: " + err.Error()))
		return
	}
	logrus.Info("Received specialization body:", string(bs))
	flr := &fission.FunctionLoadRequest{}
	err = json.Unmarshal(bs, flr)
	if err != nil {
		logrus.Errorf("Failed to parse body: %v", err)
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte("Failed to parse body: " + err.Error()))
		return
	}
	wfIDs, err := fp.specialize(ctx, flr)
	if err != nil {
		logrus.Errorf("failed to specialize: %v", err)
		if os.IsNotExist(err) {
			w.WriteHeader(http.StatusNotFound)
		} else {
			w.WriteHeader(http.StatusInternalServerError)
		}
		w.Write([]byte(err.Error()))
		return
	}
	logrus.Infof("Specialized successfully wf '%s'", wfIDs)
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(strings.Join(wfIDs, ";")))
}
func (fp *Proxy) specialize(ctx context.Context, flr *fission.FunctionLoadRequest) ([]string, error) {
	if flr == nil {
		return nil, errors.New("no function load request provided")
	}
	metadata := flr.FunctionMetadata
	if metadata == nil {
		logrus.Errorf("No workflow metadata provided: %v", metadata)
		return nil, errors.New("no metadata provided in function load request")
	}
	wfPaths, err := fp.findWorkflowFiles(ctx, flr)
	if err != nil {
		return nil, err
	}
	var wfIDs []string
	logrus.Infof("Files: %v", wfPaths)
	for _, wfPath := range wfPaths {
		wfID, err := fp.createWorkflowFromFile(ctx, flr, wfPath)
		if err != nil {
			return nil, fmt.Errorf("failed to specialize package: %v", err)
		}
		wfIDs = append(wfIDs, wfID)
	}
	return wfIDs, nil
}