routebuildermdl.go 6.92 KiB
Newer Older
Roshan Patil's avatar
Roshan Patil committed
package routebuildermdl

import (
Roshan Patil's avatar
Roshan Patil committed
	"encoding/json"
	"reflect"
	"strings"
Roshan Patil's avatar
Roshan Patil committed
	"time"

	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/constantmdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl"
Akshay Bharambe's avatar
Akshay Bharambe committed
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/servicebuildermdl"
Akshay Bharambe's avatar
Akshay Bharambe committed
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/statemdl"
	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/utiliymdl/guidmdl"
	"github.com/tidwall/gjson"
	"github.com/tidwall/sjson"
Akshay Bharambe's avatar
Akshay Bharambe committed
	Header_Branch = "Service-Branch"
)

// CleanBranch returns "main" branch if the branch string is empty after trimming all spaces. if Non-empty returns same string(including spaces along with characters).
func CleanBranch(branch string) string {
	if strings.TrimSpace(branch) == "" {
		branch = constantmdl.Branch_Main
	}

	return branch
}

func ConcatenateEntityWithBranch(name, branch string) string {

	return name + constantmdl.Branch_Separator + CleanBranch(branch)
}

Roshan Patil's avatar
Roshan Patil committed
func setResponseHeader(serviceName string) responseData {
	rd := responseData{}
	val, ok := GetResponseHeader(serviceName)
	if ok {
		rd.ResponseHeader = val
	}
	return rd
}

func executeServiceWithBranch(name, branch string, data []byte, isRestricted, isRoleBased, heavyDataActivity bool, principalObj servicebuildermdl.Principal) (interface{}, *servicebuildermdl.AbstractBusinessLogicHolder, bool, int, error) {
Kunal Taitkar's avatar
Kunal Taitkar committed

Roshan Patil's avatar
Roshan Patil committed
	start := time.Now()
	var isCompressed bool
Roshan Patil's avatar
Roshan Patil committed
	var service interface{}
	var ab *servicebuildermdl.AbstractBusinessLogicHolder
Roshan Patil's avatar
Roshan Patil committed
	var found bool
	// for calling queries as queries are not associated with any branch
	activity := name
	if name != "FetchQueryData" {
		activity = ConcatenateEntityWithBranch(name, branch)
	}
Roshan Patil's avatar
Roshan Patil committed
	if isRestricted {
		if isRoleBased {
			service, found = roleBasedServices.Get(activity)
			service, found = restrictedServices.Get(activity)
Roshan Patil's avatar
Roshan Patil committed
	} else {
		service, found = openServices.Get(activity)
Roshan Patil's avatar
Roshan Patil committed
	}
Roshan Patil's avatar
Roshan Patil committed
	if !found {
		loggermdl.LogError("Service Not Found: " + activity)
Kunal Taitkar's avatar
Kunal Taitkar committed
		return nil, ab, isCompressed, errormdl.SERVICENOTFOUND, errormdl.Wrap("Service Not Found: " + name)
Roshan Patil's avatar
Roshan Patil committed
	}
	// FetchQueryData & FetchGCData
	// We are not validating token for these two activities here.
	// we are checking & validating token inside these routes because these routes are used for open, restricted & rolebased actors.
	if isRestricted && isRoleBased && name != "FetchQueryData" && name != "FetchGCData" {
		if !validateRoleFromToken(principalObj, service.(ServiceCache)) {
			loggermdl.LogError("INVALID_ACTOR: " + name)
Kunal Taitkar's avatar
Kunal Taitkar committed
			return nil, ab, isCompressed, errormdl.SERVICENOTFOUND, errormdl.Wrap("INVALID_ACTOR: " + name)
Roshan Patil's avatar
Roshan Patil committed
	var result interface{}
	var serviceError error
	tmpServiceCache := service.(ServiceCache)
	serviceCache := tmpServiceCache
Roshan Patil's avatar
Roshan Patil committed
	if serviceCache.HeavyDataActivity {
		if !heavyDataActivity {
Kunal Taitkar's avatar
Kunal Taitkar committed
			return nil, ab, isCompressed, errormdl.SERVICENOTFOUND, errormdl.Wrap("Service is marked as heavy data... kindly use heavymql route")
Roshan Patil's avatar
Roshan Patil committed
		}
	}
	if serviceCache.AsyncService {
		asyncToken := guidmdl.GetGUID()
		data, err := sjson.SetBytes(data, "asyncToken", asyncToken)
		if errormdl.CheckErr(err) != nil {
			loggermdl.LogError(err)
Kunal Taitkar's avatar
Kunal Taitkar committed
			return nil, nil, isCompressed, errormdl.SJSONERROR, errormdl.CheckErr(err)
Roshan Patil's avatar
Roshan Patil committed
		}
		rs := gjson.ParseBytes(data)
Roshan Patil's avatar
Roshan Patil committed
		serviceCache.preHooksExec(&rs, &principalObj)
Roshan Patil's avatar
Roshan Patil committed
		go serviceCache.Service(&rs, principalObj)
		servingTime := time.Since(start)
		go statemdl.UpdateServiceStateWithBranch(name, branch, servingTime, serviceError, isRestricted, isRoleBased)
Kunal Taitkar's avatar
Kunal Taitkar committed
		return asyncToken, nil, isCompressed, errormdl.NOERROR, nil
Roshan Patil's avatar
Roshan Patil committed
	}
	rs := gjson.ParseBytes(data)
Roshan Patil's avatar
Roshan Patil committed
	// This step is actual execution of service
Roshan Patil's avatar
Roshan Patil committed
	serviceCache.preHooksExec(&rs, &principalObj)
	result, ab, serviceError = serviceCache.Service(&rs, principalObj)

Roshan Patil's avatar
Roshan Patil committed
	servingTime := time.Since(start)
	// Record State for every service
	go statemdl.UpdateServiceStateWithBranch(name, branch, servingTime, serviceError, isRestricted, isRoleBased)

	if serviceError == nil {
Roshan Patil's avatar
Roshan Patil committed
		serviceCache.postHooksExec(result, &principalObj)
Roshan Patil's avatar
Roshan Patil committed
		if serviceCache.HeavyDataActivity {
Roshan Patil's avatar
Roshan Patil committed
			isCompressed = true
Kunal Taitkar's avatar
Kunal Taitkar committed

	return result, ab, isCompressed, errormdl.EXPECTATIONFAILED, serviceError
Roshan Patil's avatar
Roshan Patil committed
}
// executeService is same as `executeServiceWithBranch` but works for `main` branch
func executeService(name string, data []byte, isRestricted, isRoleBased, heavyDataActivity bool, principalObj servicebuildermdl.Principal) (interface{}, *servicebuildermdl.AbstractBusinessLogicHolder, bool, int, error) {

	return executeServiceWithBranch(name, constantmdl.Branch_Main, data, isRestricted, isRoleBased, heavyDataActivity, principalObj)
}

func validateRoleFromToken(principalObj servicebuildermdl.Principal, service ServiceCache) bool {
	// check if group from request is present in groups associated with the service.
	for _, g := range service.Groups {
		for _, tokenGroup := range principalObj.Groups {
			if g == tokenGroup {
				return true
			}
		}
	}
	return false
}

Roshan Patil's avatar
Roshan Patil committed
func (s ServiceCache) preHooksExec(rs *gjson.Result, principalObj *servicebuildermdl.Principal) {
	for i := 0; i < len(s.PreHooks); i++ {
		var service interface{}
Kunal Taitkar's avatar
Kunal Taitkar committed
		activityName := ConcatenateEntityWithBranch(s.PreHooks[i].ActivityName, s.PreHooks[i].Branch)
Roshan Patil's avatar
Roshan Patil committed
		var found bool
		if s.PreHooks[i].ActorType == "ROLEBASED" {
Kunal Taitkar's avatar
Kunal Taitkar committed
			service, found = roleBasedServices.Get(activityName)
Roshan Patil's avatar
Roshan Patil committed
		}
		if s.PreHooks[i].ActorType == "RESTRICTED" {
Kunal Taitkar's avatar
Kunal Taitkar committed
			service, found = restrictedServices.Get(activityName)
Roshan Patil's avatar
Roshan Patil committed
		}
		if s.PreHooks[i].ActorType == "OPEN" {
Kunal Taitkar's avatar
Kunal Taitkar committed
			service, found = openServices.Get(activityName)
Roshan Patil's avatar
Roshan Patil committed
		}
		if !found {
Kunal Taitkar's avatar
Kunal Taitkar committed
			loggermdl.LogError("Pre Hook Not found: ", activityName, " for actor type: ", s.PreHooks[i].ActorType, " branch:", s.PreHooks[i].Branch)
Roshan Patil's avatar
Roshan Patil committed
			return
		}
		tmpServiceCache := service.(ServiceCache)
		serviceCache := tmpServiceCache
		go serviceCache.Service(rs, *principalObj)
	}
}

func (s ServiceCache) postHooksExec(data interface{}, principalObj *servicebuildermdl.Principal) {
	if len(s.PostHooks) == 0 {
Roshan Patil's avatar
Roshan Patil committed
	rs := gjson.Result{}
	if data != nil {
		// Fixed: Panic if data is nil.
		objType := reflect.TypeOf(data).String()
		if strings.Contains(objType, "map[string]") {
			ba, _ := json.Marshal(data)
			rs = gjson.ParseBytes(ba)
		}
Roshan Patil's avatar
Roshan Patil committed
	}
	for i := 0; i < len(s.PostHooks); i++ {
Kunal Taitkar's avatar
Kunal Taitkar committed
		activityName := ConcatenateEntityWithBranch(s.PostHooks[i].ActivityName, s.PostHooks[i].Branch)
Roshan Patil's avatar
Roshan Patil committed
		var service interface{}
		var found bool
		if s.PostHooks[i].ActorType == "ROLEBASED" {
Kunal Taitkar's avatar
Kunal Taitkar committed
			service, found = roleBasedServices.Get(activityName)
Roshan Patil's avatar
Roshan Patil committed
		}
		if s.PostHooks[i].ActorType == "RESTRICTED" {
Kunal Taitkar's avatar
Kunal Taitkar committed
			service, found = restrictedServices.Get(activityName)
Roshan Patil's avatar
Roshan Patil committed
		}
		if s.PostHooks[i].ActorType == "OPEN" {
Kunal Taitkar's avatar
Kunal Taitkar committed
			service, found = openServices.Get(activityName)
Roshan Patil's avatar
Roshan Patil committed
		}
		if !found {
Kunal Taitkar's avatar
Kunal Taitkar committed
			loggermdl.LogError("Post Hook Not found: ", activityName, " for actor type: ", s.PostHooks[i].ActorType, " Branch:", s.PostHooks[i].Branch)
Roshan Patil's avatar
Roshan Patil committed
			return
		}
		tmpServiceCache := service.(ServiceCache)
		serviceCache := tmpServiceCache
		go serviceCache.Service(&rs, *principalObj)
	}
}