Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Commit

Permalink
VCard cached repository (#203)
Browse files Browse the repository at this point in the history
* vcard cached repository

* updated CHANGELOG.md
  • Loading branch information
ortuman authored Jan 31, 2022
1 parent e44ef9e commit 0d24592
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* [ENHANCEMENT] Added memory ballast. #198
* [ENHANCEMENT] Added support for Redis cached repository. #202
* [ENHANCEMENT] Cached VCard repository. #203
* [CHANGE] Introduced measured repository transaction type. #200
* [CHANGE] Use PgSQL locker. #201
* [BUGFIX] Fix S2S db key check when nop KV is used. #199
2 changes: 1 addition & 1 deletion pkg/storage/cached/cached.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func New(cfg Config, rep repository.Repository, logger kitlog.Logger) (repositor
BlockList: rep,
Private: rep,
Roster: rep,
VCard: rep,
VCard: &cachedVCardRep{c: c, rep: rep},
Locker: rep,
rep: rep,
cache: c,
Expand Down
3 changes: 3 additions & 0 deletions pkg/storage/cached/op.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ func (op fetchOp) do(ctx context.Context) (interface{}, error) {
if err != nil {
return nil, err
}
if obj == nil {
return nil, nil
}
b, err = op.codec.encode(obj)
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion pkg/storage/cached/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func newCacheTx(c Cache, tx repository.Transaction) *cachedTx {
BlockList: tx,
Private: tx,
Roster: tx,
VCard: tx,
VCard: &cachedVCardRep{c: c, rep: tx},
Locker: tx,
}
}
7 changes: 5 additions & 2 deletions pkg/storage/cached/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,13 @@ func (c *cachedUserRep) FetchUser(ctx context.Context, username string) (*usermo
},
}
v, err := op.do(ctx)
if err != nil {
switch {
case err != nil:
return nil, err
case v != nil:
return v.(*usermodel.User), nil
}
return v.(*usermodel.User), nil
return nil, nil
}

func (c *cachedUserRep) UserExists(ctx context.Context, username string) (bool, error) {
Expand Down
96 changes: 96 additions & 0 deletions pkg/storage/cached/vcard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2022 The jackal Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cachedrepository

import (
"context"
"fmt"

"github.com/golang/protobuf/proto"
"github.com/jackal-xmpp/stravaganza/v2"
"github.com/ortuman/jackal/pkg/storage/repository"
)

type vCardCodec struct {
val stravaganza.Element
}

func (c *vCardCodec) encode(i interface{}) ([]byte, error) {
el := i.(stravaganza.Element)
return proto.Marshal(el.Proto())
}

func (c *vCardCodec) decode(b []byte) error {
sb, err := stravaganza.NewBuilderFromBinary(b)
if err != nil {
return err
}
c.val = sb.Build()
return nil
}

func (c *vCardCodec) value() interface{} {
return c.val
}

type cachedVCardRep struct {
c Cache
rep repository.VCard
}

func (c *cachedVCardRep) UpsertVCard(ctx context.Context, vCard stravaganza.Element, username string) error {
op := updateOp{
c: c.c,
key: vCardKey(username),
updateFn: func(ctx context.Context) error {
return c.rep.UpsertVCard(ctx, vCard, username)
},
}
return op.do(ctx)
}

func (c *cachedVCardRep) FetchVCard(ctx context.Context, username string) (stravaganza.Element, error) {
op := fetchOp{
c: c.c,
key: vCardKey(username),
codec: &vCardCodec{},
missFn: func(ctx context.Context) (interface{}, error) {
return c.rep.FetchVCard(ctx, username)
},
}
v, err := op.do(ctx)
switch {
case err != nil:
return nil, err
case v != nil:
return v.(stravaganza.Element), nil
}
return nil, nil
}

func (c *cachedVCardRep) DeleteVCard(ctx context.Context, username string) error {
op := updateOp{
c: c.c,
key: vCardKey(username),
updateFn: func(ctx context.Context) error {
return c.rep.DeleteVCard(ctx, username)
},
}
return op.do(ctx)
}

func vCardKey(username string) string {
return fmt.Sprintf("vc:%s", username)
}
115 changes: 115 additions & 0 deletions pkg/storage/cached/vcard_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2022 The jackal Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cachedrepository

import (
"context"
"testing"

"github.com/jackal-xmpp/stravaganza/v2"
"github.com/stretchr/testify/require"
)

func TestCachedVCardRep_UpsertVCard(t *testing.T) {
// given
var cacheKey string

cacheMock := &cacheMock{}
cacheMock.DelFunc = func(ctx context.Context, k string) error {
cacheKey = k
return nil
}

repMock := &repositoryMock{}
repMock.UpsertVCardFunc = func(ctx context.Context, vcard stravaganza.Element, username string) error {
return nil
}

// when
rep := cachedVCardRep{
c: cacheMock,
rep: repMock,
}
vCard := stravaganza.NewBuilder("vCard").Build()

err := rep.UpsertVCard(context.Background(), vCard, "u1")

// then
require.NoError(t, err)
require.Equal(t, vCardKey("u1"), cacheKey)
require.Len(t, repMock.UpsertVCardCalls(), 1)
}

func TestCachedVCardRep_DeleteVCard(t *testing.T) {
// given
var cacheKey string

cacheMock := &cacheMock{}
cacheMock.DelFunc = func(ctx context.Context, k string) error {
cacheKey = k
return nil
}

repMock := &repositoryMock{}
repMock.DeleteVCardFunc = func(ctx context.Context, username string) error {
return nil
}

// when
rep := cachedVCardRep{
c: cacheMock,
rep: repMock,
}
err := rep.DeleteVCard(context.Background(), "v1")

// then
require.NoError(t, err)
require.Equal(t, vCardKey("v1"), cacheKey)
require.Len(t, repMock.DeleteVCardCalls(), 1)
}

func TestCachedVCardRep_FetchVCard(t *testing.T) {
// given
cacheMock := &cacheMock{}
cacheMock.GetFunc = func(ctx context.Context, k string) ([]byte, error) {
return nil, nil
}
cacheMock.PutFunc = func(ctx context.Context, k string, val []byte) error {
return nil
}

repMock := &repositoryMock{}
repMock.FetchVCardFunc = func(ctx context.Context, username string) (stravaganza.Element, error) {
vCard := stravaganza.NewBuilder("vCard").Build()
return vCard, nil
}

// when
rep := cachedVCardRep{
c: cacheMock,
rep: repMock,
}
vCard, err := rep.FetchVCard(context.Background(), "u1")

// then
require.NotNil(t, vCard)
require.NoError(t, err)

require.Equal(t, "vCard", vCard.Name())

require.Len(t, cacheMock.GetCalls(), 1)
require.Len(t, cacheMock.PutCalls(), 1)
require.Len(t, repMock.FetchVCardCalls(), 1)
}

0 comments on commit 0d24592

Please sign in to comment.