// Diff two objects, and produce an RFC 6902 JSON Patch. func NewJSONPatch(a interface{}, b interface{}) (jsonpatch.JSONPatch, locale.Error) { // convert a to json aBytes, uerr := json.Marshal(a) if uerr != nil { return nil, locale.UntranslatedError(uerr) } // convert b to json bBytes, uerr := json.Marshal(b) if uerr != nil { return nil, locale.UntranslatedError(uerr) } // diff them p, uerr := matt.CreatePatch(aBytes, bBytes) if uerr != nil { return nil, locale.UntranslatedError(uerr) } pBytes, uerr := json.Marshal(p) if uerr != nil { return nil, locale.UntranslatedError(uerr) } // return var ret jsonpatch.JSONPatch uerr = json.Unmarshal(pBytes, &ret) return ret, locale.UntranslatedError(uerr) }
// Patch is a method on an application which will modify an existing Application. func (a *Application) Patch(patchedApplication *Application) (*Application, *http.Response, []error) { o, err := json.Marshal(a) if err != nil { return nil, nil, []error{err} } p, err := json.Marshal(patchedApplication) if err != nil { return nil, nil, []error{err} } patch, err := jsonpatch.CreatePatch([]byte(o), []byte(p)) if err != nil { fmt.Printf("Error creating JSON patch:%v", err) return nil, nil, []error{err} } patchBytes, err := json.Marshal(patch) if err != nil { return nil, nil, []error{err} } k := kumoru.New() k.Logger.Debugf("Patch string: %s", patchBytes) k.Patch(fmt.Sprintf("%s/v1/applications/%s", k.EndPoint.Application, a.UUID)) k.TargetType = "json-patch+json" k.RawString = string(string(patchBytes)) k.SignRequest(true) resp, body, errs := k.End() if len(errs) > 0 { return a, resp, errs } if resp.StatusCode >= 400 { errs = append(errs, fmt.Errorf("%s", resp.Status)) } pApp := Application{} err = json.Unmarshal([]byte(body), &pApp) if err != nil { errs = append(errs, err) return a, resp, errs } return &pApp, resp, nil }
//called by realtime.flusher ONLY! func (o *Object) computeUpdate() bool { //ensure only 1 update computation at a time o.mut.Lock() defer o.mut.Unlock() if o.checked { return false } //mark o.checked = true newBytes, err := json.Marshal(o.value) if err != nil { log.Printf("go-realtime: %s: marshal failed: %s", o.key, err) return false } //calculate change set ops, _ := jsonpatch.CreatePatch(o.bytes, newBytes) if len(o.bytes) > 0 && len(ops) == 0 { return false } delta, _ := json.Marshal(ops) prev := o.version o.version++ //send this new change to each subscriber for _, u := range o.subscribers { update := &update{ Key: o.key, Version: o.version, } u.mut.Lock() //choose optimal update (send the smallest) if u.versions[o.key] == prev && len(o.bytes) > 0 && len(delta) < len(o.bytes) { update.Delta = true update.Data = delta } else { update.Delta = false update.Data = newBytes } //insert pending update u.pending = append(u.pending, update) //user now has this version u.versions[o.key] = o.version u.mut.Unlock() } o.bytes = newBytes return true }