Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refact/spanner/cli #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Created by .ignore support plugin (hsz.mobi)
### Windows template
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msm
*.msp

# Windows shortcuts
*.lnk
### AppEngine template
# Google App Engine generated folder
appengine-generated/
### Eclipse template

.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders

# Eclipse Core
.project

# External tool builders
.externalToolBuilders/

# Locally stored "Eclipse launch configurations"
*.launch

# PyDev specific (Python IDE for Eclipse)
*.pydevproject

# CDT-specific (C/C++ Development Tooling)
.cproject

# JDT-specific (Eclipse Java Development Tools)
.classpath

# Java annotation processor (APT)
.factorypath

# PDT-specific (PHP Development Tools)
.buildpath

# sbteclipse plugin
.target

# Tern plugin
.tern-project

# TeXlipse plugin
.texlipse

# STS (Spring Tool Suite)
.springBeans

# Code Recommenders
.recommenders/

# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
### macOS template
*.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries

# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml

# Gradle:
.idea/**/gradle.xml
.idea/**/libraries

# Mongo Explorer plugin:
.idea/**/mongoSettings.xml

## File-based project format:
*.iws

## Plugin-specific files:

# IntelliJ
/out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Go template
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
94 changes: 52 additions & 42 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,39 +1,49 @@
package spanner_blockchain
package main

import (
"fmt"
"log"
"net/http"
// "cloud.google.com/go/spanner/admin/database/apiv1"
"cloud.google.com/go/spanner"
"cloud.google.com/go/spanner/admin/database/apiv1"
"fmt"
adminpb "google.golang.org/genproto/googleapis/spanner/admin/database/v1"
"log"
"net/http"

"crypto/sha1"
"encoding/hex"
"github.com/pkg/errors"
"golang.org/x/net/context"
"google.golang.org/api/iterator"
"google.golang.org/appengine"
"regexp"
"crypto/sha1"
"encoding/hex"
)

const (
databaseUrl = "projects/%s/instances/test-instance/database/example-db"
)

func getDatabaseName(ctx context.Context) string {
return "projects/" + appengine.AppID(ctx) + "/instances/test-instance/databases/example-db"
}
var (
spannerClient *spanner.Client
)

func main() {
sc, err := createDatabase()
if err != nil {
log.Fatal(err)
}

func init() {
// init global spanner client
spannerClient = sc

// install handler
http.HandleFunc("/write", writeData)
http.HandleFunc("/create", createDB)
log.Fatal(http.ListenAndServe("0.0.0.0:8080", nil))
}

func createDataClient(ctx context.Context, db string) *spanner.Client {
/*func getDatabaseName(ctx context.Context) string {
return fmt.Sprintf(databaseUrl, appengine.AppID(ctx))
}*/

dataClient, err := spanner.NewClient(ctx, db)
if err != nil {
log.Fatal(err)
}
return dataClient
func getDatabaseName(ctx context.Context) string {
return "projects/randommeetupgenerator/instances/test-instance/databases/example-db"
}

func createAdminClient(ctx context.Context) *database.DatabaseAdminClient {
Expand All @@ -45,15 +55,17 @@ func createAdminClient(ctx context.Context) *database.DatabaseAdminClient {
return adminClient
}

func createDatabase(ctx context.Context, client *spanner.Client, w http.ResponseWriter) error {
func createDatabase() (*spanner.Client, error) {
ctx := context.Background()

db := getDatabaseName(ctx)
adminClient := createAdminClient(ctx)

matches := regexp.MustCompile("^(.*)/databases/(.*)$").FindStringSubmatch(db)
if matches == nil || len(matches) != 3 {
return fmt.Errorf("Invalid database id %s", db)
return nil, errors.New("invalid database id" + db)
}

op, err := adminClient.CreateDatabase(ctx, &adminpb.CreateDatabaseRequest{
Parent: matches[1],
CreateStatement: "CREATE DATABASE `" + matches[2] + "`",
Expand All @@ -67,22 +79,29 @@ func createDatabase(ctx context.Context, client *spanner.Client, w http.Response
) PRIMARY KEY (BlockId)`,
},
})

if err != nil {
return err
return nil, err
}
if _, err := op.Wait(ctx); err == nil {
fmt.Fprintf(w, "Created database [%s]\n", db)
log.Println("Created database " + db)
}

client, err := spanner.NewClient(ctx, db)
if err != nil {
log.Fatal(err)
}

newMessage := "Block 0"
newMyHash := computeSha1(newMessage)
newHashBefore := ""
newHashAfter := ""

blocksColumns := []string{"BlockId", "Message", "MyHash", "HashBefore", "HashAfter"}
if err := writeMessage(blocksColumns, 1, newMessage, newMyHash, newHashBefore, newHashAfter, client, ctx); err != nil {
return err
return nil, err
}
return nil
return client, nil
}

func computeSha1(message string) string {
Expand All @@ -91,15 +110,15 @@ func computeSha1(message string) string {
h.Write([]byte(message))
sha1_hash := hex.EncodeToString(h.Sum(nil))

return sha1_hash
return sha1_hash
}

func write(ctx context.Context, client *spanner.Client, newMessage string) error {
func write(ctx context.Context, newMessage string) error {
blocksColumns := []string{"blockId", "Message", "MyHash", "HashBefore", "HashAfter"}

stmt := spanner.Statement{
SQL: `select * FROM Blocks WHERE HashAfter = ""`}
iter := client.Single().Query(ctx, stmt)
iter := spannerClient.Single().Query(ctx, stmt)
defer iter.Stop()

for {
Expand Down Expand Up @@ -137,12 +156,12 @@ func write(ctx context.Context, client *spanner.Client, newMessage string) error
newHashAfter := ""

// add new message
if err := writeMessage(blocksColumns, blockIDPrevious+1, newMessage, newMyHash, newHashBefore, newHashAfter, client, ctx); err != nil {
if err := writeMessage(blocksColumns, blockIDPrevious+1, newMessage, newMyHash, newHashBefore, newHashAfter, spannerClient, ctx); err != nil {
return err
}

// update previous message
if err := writeMessage(blocksColumns, blockIDPrevious, messagePrevious, myHashPrevious, hashBeforePrevious, newMyHash, client, ctx); err != nil {
if err := writeMessage(blocksColumns, blockIDPrevious, messagePrevious, myHashPrevious, hashBeforePrevious, newMyHash, spannerClient, ctx); err != nil {
return err
}

Expand All @@ -163,18 +182,9 @@ func writeMessage(blocksColumns []string, blockID int64, newMessage string, newM
func writeData(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Write")
message := r.URL.Query().Get("message")
if(message != "") {
c := appengine.NewContext(r)

dataClient := createDataClient(c, getDatabaseName(c))
err := write(c, dataClient, message)
if message != "" {
c := context.Background()
err := write(c, message)
fmt.Fprint(w, err)
}
}

func createDB(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
dataClient := createDataClient(c, getDatabaseName(c))
err := createDatabase(c, dataClient, w)
fmt.Fprint(w, err)
}
15 changes: 15 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"fmt"
"regexp"
"testing"
)

func TestGetDatabaseName(t *testing.T) {
db := fmt.Sprintf(databaseUrl, "randommeetupgenerator.appspot.com")
fmt.Println(db)

matches := regexp.MustCompile("^(.*)/databases/(.*)$").FindStringSubmatch(db)
fmt.Println(len(matches))
}