func (c *AppRuleController) WriteSyncErrorResponse(errMsg string, code int) {
	log.Error(errMsg)
	c.writeSyncResponse(errMsg, code)
}
Write error response
package controllers
import (
	"encoding/json"
	"errors"
	"github.com/astaxie/beego"
	log "github.com/sirupsen/logrus"
	"mecm-apprulemgr/models"
	"mecm-apprulemgr/util"
	"net/http"
	"strings"
	"unsafe"
)
const (
	appdRule                        = "appd_rule_rec"
	appdRuleId                      = "appd_rule_id"
	failedToMarshal                 = "failed to marshal request"
	lastInsertIdNotSupported        = "LastInsertId is not supported by this driver"
	toDatabase                      = "to database."
	operation                       = "] Operation ["
	resource                        = " Resource ["
	applicationJson                 = "application/json"
)
type AppRuleController struct {
	beego.Controller
	Db Database
}
func (c *AppRuleController) HealthCheck() {
	_, _ = c.Ctx.ResponseWriter.Write([]byte("ok"))
}
func (c *AppRuleController) CreateAppRuleConfig() {
	log.Info("Application Rule Config create request received.")
	c.HandleAppRuleConfig(util.Post)
}
func (c *AppRuleController) UpdateAppRuleConfig() {
	log.Info("Application Rule Config update request received.")
	c.HandleAppRuleConfig(util.Put)
}
func (c *AppRuleController) DeleteAppRuleConfig() {
	log.Info("Application Rule Config delete request received.")
	code, err := c.ValidateRequest([]string{util.MecmTenantRole, util.MecmAdminRole}, true)
	if err != nil {
		c.handleLoggingForError(code, err.Error(), "")
		return
	}
	appInstanceId := c.Ctx.Input.Param(util.AppInstanceId)
	restClient, err := createRestClient(util.CreateAppdRuleUrl(appInstanceId), util.Delete, nil)
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, err.Error(), appInstanceId)
		return
	}
	appRuleFacade := createAppRuleFacade(restClient, appInstanceId)
	response, err := appRuleFacade.handleAppRuleRequest()
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, err.Error(), appInstanceId)
		return
	}
	tenantId := c.Ctx.Input.Param(util.TenantId)
	appdRuleRecord := &models.AppdRuleRec{
		AppdRuleId: tenantId+appInstanceId,
	}
	if response.code == http.StatusOK {
		err = c.Db.DeleteData(appdRuleRecord, appdRuleId)
		if err != nil {
			c.handleLoggingForError(util.InternalServerError, "Failed to delete app rule record for id"+
				tenantId+appInstanceId+toDatabase, appInstanceId)
			return
		}
	}
	rule := &models.StaleAppdRule{AppdRuleId: tenantId + appInstanceId, TenantId: tenantId, AppInstanceId: appInstanceId}
	err = c.Db.InsertOrUpdateData(rule, appdRuleId)
	if err != nil && err.Error() != lastInsertIdNotSupported {
		c.handleLoggingForError(util.InternalServerError, "Failed to save app rule record for id"+
			rule.AppdRuleId+toDatabase, appInstanceId)
		return
	}
	progressModelBytes, err := json.Marshal(response.progressModel)
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, util.MarshalProgressModelError, appInstanceId)
		return
	}
	c.WriteResponse(progressModelBytes, response.code)
}
func (c *AppRuleController) GetAppRuleConfig() {
	log.Info("Application Rule Config get request received.")
	code, err := c.ValidateRequest([]string{util.MecmTenantRole, util.MecmAdminRole, util.MecmGuestRole}, true)
	if err != nil {
		c.handleLoggingForError(code, err.Error(), "")
		return
	}
	appInstanceId := c.Ctx.Input.Param(util.AppInstanceId)
	restClient, err := createRestClient(util.CreateAppdRuleUrl(appInstanceId), util.Get, nil)
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, err.Error(), appInstanceId)
		return
	}
	appRuleFacade := createAppRuleFacade(restClient, appInstanceId)
	response, err := appRuleFacade.handleAppRuleGetRequest()
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, err.Error(), appInstanceId)
		return
	}
	if response.code == http.StatusOK {
		appRuleModelBytes, err := json.Marshal(response.appdrule)
		if err != nil {
			c.handleLoggingForError(util.InternalServerError, util.MarshalAppRuleModelError, appInstanceId)
			return
		}
		c.WriteResponse(appRuleModelBytes, response.code)
		return
	}
	progressModelBytes, err := json.Marshal(response.progressModel)
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, util.MarshalProgressModelError, appInstanceId)
		return
	}
	c.WriteResponse(progressModelBytes, response.code)
}
func (c *AppRuleController) handleLoggingForError(code int, errMsg string, appInstanceId string) {
	c.WriteErrorResponse(errMsg, code, appInstanceId)
	clientIp := c.Ctx.Input.IP()
	log.Info("Response message for ClientIP [" + clientIp + operation + c.Ctx.Request.Method + "]" +
		resource + c.Ctx.Input.URL() + "] Result [Failure: " + errMsg + ".]")
}
func (c *AppRuleController) WriteErrorResponse(errMsg string, code int, appInstanceId string) {
	progressModel := util.CreateOperationProgressModel(appInstanceId, util.Failure, errMsg)
	progressModelBytes, err := json.Marshal(progressModel)
	if err != nil {
		log.Error(util.MarshalProgressModelError)
		return
	}
	log.Error(errMsg)
	c.WriteResponse(progressModelBytes, code)
}
func (c *AppRuleController) WriteResponse(msg []byte, code int) {
	c.Ctx.Output.SetStatus(code)
	err := c.Ctx.Output.Body(msg)
	if err != nil {
		log.Error(util.FailedToWriteRes)
	}
}
func (c *AppRuleController) displayReceivedMsg(clientIp string) {
	log.Info("Received message from ClientIP [" + clientIp + operation + c.Ctx.Request.Method + "]" +
		resource + c.Ctx.Input.URL() + "]")
}
func (c *AppRuleController) validateApiParams() error {
	appInstanceId := c.Ctx.Input.Param(util.AppInstanceId)
	if appInstanceId != "" {
		err := util.ValidateUUID(appInstanceId)
		if err != nil {
			return errors.New(util.AppInstanceIdInvalid)
		}
	}
	tenantId := c.Ctx.Input.Param(util.TenantId)
	err := util.ValidateUUID(tenantId)
	if err != nil {
		return errors.New(util.TenantIdInvalid)
	}
	return nil
}
func (c *AppRuleController) ValidateAppRuleModel() (*models.AppdRule, error) {
	if len(c.Ctx.Input.RequestBody) > util.RequestBodyLength {
		return nil, errors.New(util.RequestBodyTooLarge)
	}
	var appRuleConfig *models.AppdRule
	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &appRuleConfig); err != nil {
		log.Error("failed to unmarshal")
		return nil, errors.New(util.UnMarshalAppRuleModelError)
	}
	err := util.ValidateRestBody(appRuleConfig)
	if err != nil {
		log.Error("failed to validate rest body")
		return nil, err
	}
	return appRuleConfig, nil
}
func (c *AppRuleController) ValidateRequest(allowedRoles []string, isAppInstanceAvailable bool) (int, error) {
	clientIp := c.Ctx.Input.IP()
	err := util.ValidateIpv4Address(clientIp)
	if err != nil {
		return util.BadRequest, errors.New(util.ClientIpaddressInvalid)
	}
	c.displayReceivedMsg(clientIp)
	accessToken := c.Ctx.Request.Header.Get(util.AccessToken)
	tenantId := c.Ctx.Input.Param(util.TenantId)
	err = util.ValidateAccessToken(accessToken, allowedRoles, tenantId)
	if err != nil {
		if err.Error() == util.Forbidden {
			return util.StatusForbidden, errors.New(util.Forbidden)
		} else {
			return util.StatusUnauthorized, errors.New(util.AuthorizationFailed)
		}
	}
	bKey := *(*[]byte)(unsafe.Pointer(&accessToken))
	util.ClearByteArray(bKey)
	err = c.validateApiParams()
	if err != nil {
		return util.BadRequest, err
	}
	return 0, nil
}
func (c *AppRuleController) HandleAppRuleConfig(method string) {
	code, err := c.ValidateRequest([]string{util.MecmTenantRole, util.MecmAdminRole}, true)
	if err != nil {
		c.handleLoggingForError(code, err.Error(), "")
		return
	}
	appInstanceId := c.Ctx.Input.Param(util.AppInstanceId)
	err = util.ValidateUUID(appInstanceId)
	if err != nil {
		c.handleLoggingForError(code, err.Error(), "")
		return
	}
	appRuleConfig, err := c.ValidateAppRuleModel()
	if err != nil {
		c.handleLoggingForError(util.BadRequest, err.Error(), appInstanceId)
		return
	}
	restClient, err := createRestClient(util.CreateAppdRuleUrl(appInstanceId), method, appRuleConfig)
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, err.Error(), appInstanceId)
		return
	}
	appRuleFacade := createAppRuleFacade(restClient, appInstanceId)
	response, err := appRuleFacade.handleAppRuleRequest()
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, err.Error(), appInstanceId)
		return
	}
	origin := c.Ctx.Request.Header.Get("origin")
	originVar, err := util.ValidateName(origin, util.NameRegex)
	if err != nil || !originVar {
		c.handleLoggingForError(util.BadRequest, err.Error(), appInstanceId)
		return
	}
	syncStatus := true
	if origin == "MEPM" {
		syncStatus = false
	}
	tenantId := c.Ctx.Input.Param(util.TenantId)
	err = util.ValidateUUID(tenantId)
	if err != nil {
		c.handleLoggingForError(util.BadRequest, err.Error(), appInstanceId)
		return
	}
	appdRuleRecord := &models.AppdRuleRec{
		AppdRuleId: tenantId+appInstanceId,
	}
	_ = c.Db.DeleteData(appdRuleRecord, appdRuleId)
	appdRuleRec := &models.AppdRuleRec{
		AppdRuleId: tenantId + appInstanceId,
		TenantId: tenantId,
		AppInstanceId: appInstanceId,
		AppName:  appRuleConfig.AppName,
		AppSupportMp1: appRuleConfig.AppSupportMp1,
		SyncStatus: syncStatus,
		Origin     : origin,
	}
	err = c.Db.InsertOrUpdateData(appdRuleRec, "appd_rule_id")
	if err != nil && err.Error() != lastInsertIdNotSupported {
		c.handleLoggingForError(util.InternalServerError, "Failed to save appd rule record for id"+
			appdRuleRec.AppdRuleId+toDatabase, appInstanceId)
		return
	}
	err = c.InsertOrUpdateAppTrafficRuleRec(appRuleConfig, appdRuleRec, appInstanceId)
	if err != nil {
		log.Error("failed to insert app traffic rule record")
		return
	}
	err = c.insertOrUpdateAppDnsRuleRec(appRuleConfig, appdRuleRec, appInstanceId)
	if err != nil {
		log.Error("failed to insert dns rule record")
		return
	}
	progressModelBytes, err := json.Marshal(response.progressModel)
	if err != nil {
		c.handleLoggingForError(util.InternalServerError, util.MarshalProgressModelError, appInstanceId)
		return
	}
	c.WriteResponse(progressModelBytes, response.code)
}
func (c *AppRuleController) SynchronizeUpdatedRecords() {
	log.Info("Sync app config request received.")
	var syncUpdatedRulesRecords models.SyncUpdatedRulesRecords
	clientIp := c.Ctx.Input.IP()
	code, err := c.ValidateRequest([]string{util.MecmTenantRole, util.MecmAdminRole}, false)
	if err != nil {
		c.HandleLoggingForSyncError(clientIp, code, err.Error())
		return
	}
	appdRulesSync := c.getAppdRuleSyncInfo()
	syncUpdatedRulesRecords.AppdRuleUpdatedRecs = append(syncUpdatedRulesRecords.AppdRuleUpdatedRecs, appdRulesSync...)
	syncUpdatedRulesRecs := c.GetSyncUpdatedRulesRecs(syncUpdatedRulesRecords)
	c.SendSyncUpdatedRulesRecs(syncUpdatedRulesRecs, appdRulesSync, clientIp)
}
func (c *AppRuleController) SynchronizeDeletedRecords() {
	log.Info("Sync deleted app rule records request received.")
	var staleRules []models.StaleAppdRule
	var syncDeletedRulesRecords models.SyncDeletedRulesRecords
	clientIp := c.Ctx.Input.IP()
	err := util.ValidateIpv4Address(clientIp)
	if err != nil {
		c.WriteSyncErrorResponse("invalid ip address", util.BadRequest)
		return
	}
	code, err := c.ValidateRequest([]string{util.MecmTenantRole, util.MecmAdminRole}, false)
	if err != nil {
		c.HandleLoggingForSyncError(clientIp, code, err.Error())
		return
	}
	_, _ = c.Db.QueryTable("stale_appd_rule", &staleRules, "tenant_id", c.Ctx.Input.Param(util.TenantId))
	syncDeletedRulesRecords.AppdRuleDeletedRecs = append(syncDeletedRulesRecords.AppdRuleDeletedRecs, staleRules...)
	appRuleModelBytes, err := json.Marshal(syncDeletedRulesRecords)
	if err != nil {
		c.WriteSyncErrorResponse(failedToMarshal, util.BadRequest)
		return
	}
	c.Ctx.ResponseWriter.Header().Set("Content-Type", applicationJson)
	c.Ctx.ResponseWriter.Header().Set("Accept", applicationJson)
	_, _ = c.Ctx.ResponseWriter.Write(appRuleModelBytes)
	for _, staleRule := range staleRules {
		err = c.Db.DeleteData(&staleRule, appdRuleId)
		if err != nil && err.Error() != lastInsertIdNotSupported {
			c.HandleLoggingForSyncError(clientIp, util.InternalServerError, "Failed to delete stale data in " +
				"database with error: ." + err.Error())
			return
		}
	}
}