2023-05-10 02:37:58 +08:00
|
|
|
package msgpatch
|
|
|
|
|
|
|
|
import (
|
2024-08-09 03:50:41 +08:00
|
|
|
"bbb-graphql-middleware/internal/common"
|
2023-05-10 02:37:58 +08:00
|
|
|
"encoding/json"
|
|
|
|
"github.com/mattbaird/jsonpatch"
|
|
|
|
log "github.com/sirupsen/logrus"
|
2024-06-25 21:27:44 +08:00
|
|
|
"strconv"
|
2023-05-10 02:37:58 +08:00
|
|
|
)
|
|
|
|
|
2024-08-19 21:58:14 +08:00
|
|
|
var minLengthToPatch = 250 //250 chars
|
|
|
|
var minShrinkToUsePatch = 0.5 //50% percent
|
2024-04-06 22:43:36 +08:00
|
|
|
|
2024-06-25 21:27:44 +08:00
|
|
|
func GetPatchedMessage(
|
|
|
|
receivedMessage []byte,
|
2024-04-06 22:43:36 +08:00
|
|
|
dataKey string,
|
2024-06-25 21:27:44 +08:00
|
|
|
lastHasuraMessage common.HasuraMessage,
|
|
|
|
hasuraMessage common.HasuraMessage,
|
|
|
|
cacheKey uint32,
|
2024-04-06 22:43:36 +08:00
|
|
|
lastDataChecksum uint32,
|
2024-06-25 21:27:44 +08:00
|
|
|
currDataChecksum uint32) []byte {
|
2024-04-06 22:43:36 +08:00
|
|
|
|
|
|
|
if lastDataChecksum != 0 {
|
2024-06-25 21:27:44 +08:00
|
|
|
common.JsonPatchBenchmarkingStarted(strconv.Itoa(int(cacheKey)))
|
|
|
|
defer common.JsonPatchBenchmarkingCompleted(strconv.Itoa(int(cacheKey)))
|
2024-04-06 22:43:36 +08:00
|
|
|
}
|
|
|
|
|
2024-06-25 21:27:44 +08:00
|
|
|
//Lock to avoid other routines from processing the same message
|
2024-04-06 22:43:36 +08:00
|
|
|
common.GlobalCacheLocks.Lock(cacheKey)
|
2024-06-25 21:27:44 +08:00
|
|
|
if patchedMessageCache, patchedMessageCacheExists := common.GetPatchedMessageCache(cacheKey); patchedMessageCacheExists {
|
2024-04-06 22:43:36 +08:00
|
|
|
//Unlock immediately once the cache was already created by other routine
|
|
|
|
common.GlobalCacheLocks.Unlock(cacheKey)
|
2024-06-25 21:27:44 +08:00
|
|
|
return patchedMessageCache
|
2024-04-06 22:43:36 +08:00
|
|
|
} else {
|
|
|
|
//It will create the cache and then Unlock (others will wait to benefit from this cache)
|
|
|
|
defer common.GlobalCacheLocks.Unlock(cacheKey)
|
|
|
|
}
|
|
|
|
|
2024-06-25 21:27:44 +08:00
|
|
|
var jsonDiffPatch []byte
|
2023-05-10 02:37:58 +08:00
|
|
|
|
2024-06-25 21:27:44 +08:00
|
|
|
if currDataChecksum == lastDataChecksum {
|
|
|
|
//Content didn't change, set message as null to avoid sending it to the browser
|
|
|
|
//This case is usual when the middleware reconnects with Hasura and receives the data again
|
|
|
|
jsonData, _ := json.Marshal(nil)
|
|
|
|
common.StorePatchedMessageCache(cacheKey, jsonData)
|
|
|
|
return jsonData
|
|
|
|
} else {
|
|
|
|
//Content was changed, creating json patch
|
|
|
|
//If data is small (< minLengthToPatch) it's not worth creating the patch
|
|
|
|
if len(hasuraMessage.Payload.Data[dataKey]) > minLengthToPatch {
|
2024-08-19 21:58:14 +08:00
|
|
|
if string(lastHasuraMessage.Payload.Data[dataKey]) != "" {
|
2024-06-25 21:27:44 +08:00
|
|
|
var shouldUseCustomJsonPatch bool
|
2024-08-19 21:58:14 +08:00
|
|
|
if shouldUseCustomJsonPatch, jsonDiffPatch = common.ValidateIfShouldUseCustomJsonPatch(
|
|
|
|
lastHasuraMessage.Payload.Data[dataKey],
|
|
|
|
hasuraMessage.Payload.Data[dataKey],
|
|
|
|
"userId"); shouldUseCustomJsonPatch {
|
2024-06-25 21:27:44 +08:00
|
|
|
common.StorePatchedMessageCache(cacheKey, jsonDiffPatch)
|
2024-08-19 21:58:14 +08:00
|
|
|
} else if diffPatch, diffPatchErr := jsonpatch.CreatePatch(lastHasuraMessage.Payload.Data[dataKey], hasuraMessage.Payload.Data[dataKey]); diffPatchErr == nil {
|
2024-06-25 21:27:44 +08:00
|
|
|
var err error
|
|
|
|
if jsonDiffPatch, err = json.Marshal(diffPatch); err != nil {
|
|
|
|
log.Errorf("Error marshaling patch array: %v", err)
|
2024-04-06 22:43:36 +08:00
|
|
|
}
|
2024-06-25 21:27:44 +08:00
|
|
|
} else {
|
|
|
|
log.Errorf("Error creating JSON patch: %v\n%v", diffPatchErr, string(hasuraMessage.Payload.Data[dataKey]))
|
2023-05-25 06:31:31 +08:00
|
|
|
}
|
2023-05-10 02:37:58 +08:00
|
|
|
}
|
2024-02-02 23:36:27 +08:00
|
|
|
}
|
2024-04-06 22:43:36 +08:00
|
|
|
}
|
2023-05-25 06:31:31 +08:00
|
|
|
|
2024-04-06 22:43:36 +08:00
|
|
|
//Use patch if the length is {minShrinkToUsePatch}% smaller than the original msg
|
2024-06-25 21:27:44 +08:00
|
|
|
if jsonDiffPatch != nil && float64(len(string(jsonDiffPatch)))/float64(len(string(hasuraMessage.Payload.Data[dataKey]))) < minShrinkToUsePatch {
|
2024-04-06 22:43:36 +08:00
|
|
|
//Modify receivedMessage to include the Patch and remove the previous data
|
|
|
|
//The key of the original message is kept to avoid errors (Apollo-client expects to receive this prop)
|
2024-06-25 21:27:44 +08:00
|
|
|
|
|
|
|
hasuraMessage.Payload.Data = map[string]json.RawMessage{
|
|
|
|
"patch": jsonDiffPatch,
|
|
|
|
dataKey: json.RawMessage("[]"),
|
2024-04-06 22:43:36 +08:00
|
|
|
}
|
2024-06-25 21:27:44 +08:00
|
|
|
hasuraMessageJson, _ := json.Marshal(hasuraMessage)
|
|
|
|
receivedMessage = hasuraMessageJson
|
2024-04-06 22:43:36 +08:00
|
|
|
}
|
|
|
|
|
2024-06-25 21:27:44 +08:00
|
|
|
common.StorePatchedMessageCache(cacheKey, receivedMessage)
|
|
|
|
return receivedMessage
|
2023-05-10 02:37:58 +08:00
|
|
|
}
|