Skip to content

Commit b576869

Browse files
authoredMar 16, 2024
Merge pull request #62 from Hu6li/client
Implementation of small client
2 parents c9656b0 + dc67db0 commit b576869

File tree

3 files changed

+228
-0
lines changed

3 files changed

+228
-0
lines changed
 

‎client/client.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"encoding/json"
7+
"flag"
8+
"fmt"
9+
10+
"cloud.google.com/go/spanner"
11+
"github.com/google/hashr/client/cloudspanner"
12+
"github.com/google/hashr/client/postgres"
13+
_ "github.com/lib/pq"
14+
15+
"github.com/golang/glog"
16+
)
17+
18+
var (
19+
hashStorage = flag.String("hashStorage", "", "Storage used for computed hashes, can have one of the two values: postgres, cloudspanner")
20+
spannerDBPath = flag.String("spanner_db_path", "", "Path to spanner DB.")
21+
22+
// Postgres DB flags
23+
postgresHost = flag.String("postgres_host", "localhost", "PostgreSQL instance address.")
24+
postgresPort = flag.Int("postgres_port", 5432, "PostgresSQL instance port.")
25+
postgresUser = flag.String("postgres_user", "hashr", "PostgresSQL user.")
26+
postgresPassword = flag.String("postgres_password", "hashr", "PostgresSQL password.")
27+
postgresDBName = flag.String("postgres_db", "hashr", "PostgresSQL database.")
28+
)
29+
30+
// Storage represents storage that is used to store data about processed sources.
31+
type Storage interface {
32+
GetSamples(ctx context.Context) (map[string]map[string]string, error)
33+
}
34+
35+
func main() {
36+
ctx := context.Background()
37+
flag.Parse()
38+
39+
var storage Storage
40+
switch *hashStorage {
41+
case "postgres":
42+
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
43+
*postgresHost, *postgresPort, *postgresUser, *postgresPassword, *postgresDBName)
44+
45+
db, err := sql.Open("postgres", psqlInfo)
46+
if err != nil {
47+
glog.Exitf("Error initializing Postgres client: %v", err)
48+
}
49+
defer db.Close()
50+
51+
storage, err = postgres.NewStorage(db)
52+
if err != nil {
53+
glog.Exitf("Error initializing Postgres storage: %v", err)
54+
}
55+
case "cloudspanner":
56+
spannerClient, err := spanner.NewClient(ctx, *spannerDBPath)
57+
if err != nil {
58+
glog.Exitf("Error initializing Spanner client: %v", err)
59+
}
60+
61+
storage, err = cloudspanner.NewStorage(ctx, spannerClient)
62+
if err != nil {
63+
glog.Exitf("Error initializing Postgres storage: %v", err)
64+
}
65+
default:
66+
glog.Exit("hashStorage flag needs to have one of the two values: postgres, cloudspanner")
67+
68+
}
69+
samples, err := storage.GetSamples(ctx)
70+
if err != nil {
71+
glog.Exitf("Error retriving samples: %v", err)
72+
}
73+
74+
jsonData, err := json.Marshal(samples)
75+
if err != nil {
76+
fmt.Println("Error:", err)
77+
return
78+
}
79+
80+
fmt.Println(string(jsonData))
81+
}

‎client/cloudspanner/cloudspanner.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package cloudspanner
2+
3+
import (
4+
"context"
5+
"strconv"
6+
7+
"cloud.google.com/go/spanner"
8+
9+
"google.golang.org/api/iterator"
10+
)
11+
12+
// Storage allows to interact with cloud spanner.
13+
type Storage struct {
14+
spannerClient *spanner.Client
15+
}
16+
17+
// NewStorage creates new Storage struct that allows to interact with cloud spanner.
18+
func NewStorage(ctx context.Context, spannerClient *spanner.Client) (*Storage, error) {
19+
return &Storage{spannerClient: spannerClient}, nil
20+
}
21+
22+
// GetSamples fetches processing samples from cloud spanner.
23+
func (s *Storage) GetSamples(ctx context.Context) (map[string]map[string]string, error) {
24+
samples := make(map[string]map[string]string)
25+
iter := s.spannerClient.Single().Read(ctx, "samples",
26+
spanner.AllKeys(), []string{"sha256", "mimetype", "file_output", "size"})
27+
defer iter.Stop()
28+
for {
29+
row, err := iter.Next()
30+
if err == iterator.Done {
31+
break
32+
}
33+
if err != nil {
34+
return nil, err
35+
}
36+
var sha256, mimetype, fileOutput string
37+
var size int64
38+
err = row.ColumnByName("sha256", &sha256)
39+
if err != nil {
40+
return nil, err
41+
}
42+
err = row.ColumnByName("mimetype", &mimetype)
43+
if err != nil {
44+
return nil, err
45+
}
46+
err = row.ColumnByName("file_output", &fileOutput)
47+
if err != nil {
48+
return nil, err
49+
}
50+
err = row.ColumnByName("size", &size)
51+
if err != nil {
52+
return nil, err
53+
}
54+
samples[sha256] = make(map[string]string)
55+
56+
// Assign values to the nested map
57+
samples[sha256]["sha256"] = sha256
58+
samples[sha256]["mimetype"] = mimetype
59+
samples[sha256]["file_output"] = fileOutput
60+
samples[sha256]["size"] = strconv.FormatInt(size, 10)
61+
62+
}
63+
return samples, nil
64+
}

‎client/postgres/postgres.go

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Package postgres implements PostgreSQL as a hashR storage.
2+
package postgres
3+
4+
import (
5+
"context"
6+
"database/sql"
7+
"fmt"
8+
9+
// Blank import below is needed for the SQL driver.
10+
_ "github.com/lib/pq"
11+
)
12+
13+
// Storage allows to interact with PostgreSQL instance.
14+
type Storage struct {
15+
sqlDB *sql.DB
16+
}
17+
18+
// NewStorage creates new Storage struct that allows to interact with PostgreSQL instance and all the necessary tables, if they don't exist.
19+
func NewStorage(sqlDB *sql.DB) (*Storage, error) {
20+
return &Storage{sqlDB: sqlDB}, nil
21+
}
22+
23+
// GetSamples fetches processed samples from postgres.
24+
func (s *Storage) GetSamples(ctx context.Context) (map[string]map[string]string, error) {
25+
exists, err := tableExists(s.sqlDB, "samples")
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
samples := make(map[string]map[string]string)
31+
32+
if exists {
33+
var sql = `SELECT * FROM samples;`
34+
35+
rows, err := s.sqlDB.Query(sql)
36+
37+
if err != nil {
38+
return nil, err
39+
}
40+
41+
defer rows.Close()
42+
43+
for rows.Next() {
44+
var sha256, mimetype, fileOutput, size string
45+
err := rows.Scan(&sha256, &mimetype, &fileOutput, &size)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
samples[sha256] = make(map[string]string)
51+
52+
// Assign values to the nested map
53+
samples[sha256]["sha256"] = sha256
54+
samples[sha256]["mimetype"] = mimetype
55+
samples[sha256]["file_output"] = fileOutput
56+
samples[sha256]["size"] = size
57+
}
58+
59+
} else {
60+
return nil, fmt.Errorf("table samples does not exist")
61+
}
62+
63+
return samples, nil
64+
}
65+
66+
func tableExists(db *sql.DB, tableName string) (bool, error) {
67+
// Query to check if the table exists in PostgreSQL
68+
query := `
69+
SELECT EXISTS (
70+
SELECT 1
71+
FROM information_schema.tables
72+
WHERE table_name = $1
73+
)
74+
`
75+
76+
var exists bool
77+
err := db.QueryRow(query, tableName).Scan(&exists)
78+
if err != nil {
79+
return false, err
80+
}
81+
82+
return exists, nil
83+
}

0 commit comments

Comments
 (0)