Skip to content

Commit

Permalink
Merge pull request #80 from brotherlogic/add_mongo_client
Browse files Browse the repository at this point in the history
Ensure we use the redis client
  • Loading branch information
brotherlogic committed Jun 11, 2024
2 parents 18793ee + 638fa0c commit bffb482
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 61 deletions.
58 changes: 58 additions & 0 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL"

on:
pull_request:
# The branches below must be a subset of the branches above
branches: [main]

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['go']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection

steps:
- name: Checkout repository
uses: actions/checkout@v2

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
76 changes: 19 additions & 57 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"log"
"net"
"net/http"
"strings"
"time"

ghbpb "github.com/brotherlogic/githubridge/proto"
Expand All @@ -18,9 +17,6 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/redis/go-redis/v9"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/anypb"

"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
Expand All @@ -37,73 +33,37 @@ var (

type Server struct {
rdb *redis.Client
mongo *mongo.Client
gclient ghbclient.GithubridgeClient

redisClient *redisClient
mongoClient *mongoClient

cache map[string][]byte
}

func (s *Server) Read(ctx context.Context, req *pb.ReadRequest) (*pb.ReadResponse, error) {
/*if val, ok := s.cache[req.GetKey()]; ok {
return &pb.ReadResponse{Value: &anypb.Any{Value: val}}, nil
}*/
cmd := s.rdb.Get(ctx, req.GetKey())
result, err := cmd.Bytes()

if err == redis.Nil {
return nil, status.Errorf(codes.NotFound, "key %v was not found", req.GetKey())
}
type rstore interface {
Read(ctx context.Context, req *pb.ReadRequest) (*pb.ReadResponse, error)
Write(ctx context.Context, req *pb.WriteRequest) (*pb.WriteResponse, error)
GetKeys(ctx context.Context, req *pb.GetKeysRequest) (*pb.GetKeysResponse, error)
Delete(ctx context.Context, req *pb.DeleteRequest) (*pb.DeleteResponse, error)
}

if err != nil {
log.Printf("remote err on read: %v", err)
}
return &pb.ReadResponse{Value: &anypb.Any{Value: result}}, err
func (s *Server) Read(ctx context.Context, req *pb.ReadRequest) (*pb.ReadResponse, error) {
return s.redisClient.Read(ctx, req)
}

func (s *Server) Write(ctx context.Context, req *pb.WriteRequest) (*pb.WriteResponse, error) {
err := s.rdb.Set(ctx, req.GetKey(), req.GetValue().GetValue(), 0).Err()
if err != nil {
log.Printf("remote err on write: %v", err)
} else {
//s.cache[req.GetKey()] = req.GetValue().GetValue()
}
return &pb.WriteResponse{}, err
// On the write path, do a fire or forget write into Mongo
s.mongoClient.Write(ctx, req)
return s.redisClient.Write(ctx, req)
}

func (s *Server) GetKeys(ctx context.Context, req *pb.GetKeysRequest) (*pb.GetKeysResponse, error) {
var akeys []string
t := time.Now()
defer func(t time.Time) {
log.Printf("Completed %v in %v", req.GetPrefix(), time.Since(t))
}(t)
iter := s.rdb.Scan(ctx, 0, fmt.Sprintf("%v*", req.GetPrefix()), 1000).Iterator()

for iter.Next(ctx) {
key := iter.Val()
if req.GetAllKeys() || strings.Count(key, "/") == strings.Count(req.GetPrefix(), "/") {
valid := true
for _, suffix := range req.GetAvoidSuffix() {
if strings.HasSuffix(key, suffix) {
valid = false
}
}
if valid {
akeys = append(akeys, key)
}
}
}

if err := iter.Err(); err != nil {
log.Printf("Failed to read keys (%v) in %v", req.GetPrefix(), time.Since(t))
return nil, fmt.Errorf("database error reading keys %w", err)
}

log.Printf("returning %v items (%v)", len(akeys), req.GetPrefix())
return &pb.GetKeysResponse{Keys: akeys}, nil
return s.redisClient.GetKeys(ctx, req)
}

func (s *Server) Delete(ctx context.Context, req *pb.DeleteRequest) (*pb.DeleteResponse, error) {
return &pb.DeleteResponse{}, s.rdb.Del(ctx, req.GetKey()).Err()
return s.redisClient.Delete(ctx, req)
}

func main() {
Expand All @@ -128,6 +88,8 @@ func main() {
panic(err)
}

s.redisClient = &redisClient{rdb: s.rdb}

mclient, err := mongo.Connect(ctx, options.Client().ApplyURI(*mongoAddress))
defer func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
Expand All @@ -139,7 +101,7 @@ func main() {
if err != nil {
panic(err)
}
s.mongo = mclient
s.mongoClient = &mongoClient{client: mclient}

err = mclient.Ping(ctx, readpref.Primary())
if err != nil {
Expand Down
23 changes: 19 additions & 4 deletions mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,27 @@ import (
"context"

pb "github.com/brotherlogic/rstore/proto"
"google.golang.org/protobuf/types/known/anypb"
"go.mongodb.org/mongo-driver/mongo"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type Mongo struct {
type mongoClient struct {
client *mongo.Client
}

func (m *Mongo) Read(ctx context.Context, req *pb.ReadRequest) (*pb.ReadResponse, error) {
return &pb.ReadResponse{Value: &anypb.Any{}}, nil
func (m *mongoClient) Read(ctx context.Context, req *pb.ReadRequest) (*pb.ReadResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Unimplmented")
}

func (m *mongoClient) Write(ctx context.Context, req *pb.WriteRequest) (*pb.WriteResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Unimplmented")
}

func (m *mongoClient) GetKeys(ctx context.Context, req *pb.GetKeysRequest) (*pb.GetKeysResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Unimplmented")
}

func (m *mongoClient) Delete(ctx context.Context, req *pb.DeleteRequest) (*pb.DeleteResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Unimplmented")
}
82 changes: 82 additions & 0 deletions redis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package main

import (
"context"
"fmt"
"log"
"strings"
"time"

pb "github.com/brotherlogic/rstore/proto"
"github.com/redis/go-redis/v9"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/anypb"
)

type redisClient struct {
rdb *redis.Client
}

func (r *redisClient) Read(ctx context.Context, req *pb.ReadRequest) (*pb.ReadResponse, error) {
/*if val, ok := s.cache[req.GetKey()]; ok {
return &pb.ReadResponse{Value: &anypb.Any{Value: val}}, nil
}*/
cmd := r.rdb.Get(ctx, req.GetKey())
result, err := cmd.Bytes()

if err == redis.Nil {
return nil, status.Errorf(codes.NotFound, "key %v was not found", req.GetKey())
}

if err != nil {
log.Printf("remote err on read: %v", err)
}
return &pb.ReadResponse{Value: &anypb.Any{Value: result}}, err
}

func (r *redisClient) Write(ctx context.Context, req *pb.WriteRequest) (*pb.WriteResponse, error) {
err := r.rdb.Set(ctx, req.GetKey(), req.GetValue().GetValue(), 0).Err()
if err != nil {
log.Printf("remote err on write: %v", err)
} else {
//s.cache[req.GetKey()] = req.GetValue().GetValue()
}
return &pb.WriteResponse{}, err
}

func (r *redisClient) GetKeys(ctx context.Context, req *pb.GetKeysRequest) (*pb.GetKeysResponse, error) {
var akeys []string
t := time.Now()
defer func(t time.Time) {
log.Printf("Completed %v in %v", req.GetPrefix(), time.Since(t))
}(t)
iter := r.rdb.Scan(ctx, 0, fmt.Sprintf("%v*", req.GetPrefix()), 1000).Iterator()

for iter.Next(ctx) {
key := iter.Val()
if req.GetAllKeys() || strings.Count(key, "/") == strings.Count(req.GetPrefix(), "/") {
valid := true
for _, suffix := range req.GetAvoidSuffix() {
if strings.HasSuffix(key, suffix) {
valid = false
}
}
if valid {
akeys = append(akeys, key)
}
}
}

if err := iter.Err(); err != nil {
log.Printf("Failed to read keys (%v) in %v", req.GetPrefix(), time.Since(t))
return nil, fmt.Errorf("database error reading keys %w", err)
}

log.Printf("returning %v items (%v)", len(akeys), req.GetPrefix())
return &pb.GetKeysResponse{Keys: akeys}, nil
}

func (r *redisClient) Delete(ctx context.Context, req *pb.DeleteRequest) (*pb.DeleteResponse, error) {
return &pb.DeleteResponse{}, r.rdb.Del(ctx, req.GetKey()).Err()
}

0 comments on commit bffb482

Please sign in to comment.