Skip to content

Commit

Permalink
Removed Token struct. A string is good enough - at least for now
Browse files Browse the repository at this point in the history
  • Loading branch information
muesli committed Jun 3, 2017
1 parent c8c6f31 commit e31a6c5
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 51 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@ func main() {
// Distance is calculated by insertion cost (1), deletion cost (1) and substitution cost (2)
for i := 0; i < 9; i++ {
token, _ := bucket.NewToken(4)
fmt.Printf("Generated Token %d: %s\n", i, token.Code)
fmt.Printf("Generated Token %d: %s\n", i, token)
}

// One more token that we will tamper with
token, _ := bucket.NewToken(4)
fmt.Printf("Generated Token 9: %s\n", token.Code)
token.Code = "_" + token.Code[1:7] + "_"
fmt.Printf("Generated Token 9: %s\n", token)
token = "_" + token[1:7] + "_"

// Find the closest match for the faulty token
match, distance := bucket.Resolve(token.Code)
fmt.Printf("Best match for '%s' is token '%s' with distance %d\n", token.Code, match.Code, distance)
match, distance := bucket.Resolve(token)
fmt.Printf("Best match for '%s' is token '%s' with distance %d\n", token, match, distance)
}
```

Expand Down
10 changes: 5 additions & 5 deletions examples/tokens/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ func main() {
// Distance is calculated by insertion cost (1), deletion cost (1) and substitution cost (2)
for i := 0; i < 9; i++ {
token, _ := bucket.NewToken(4)
fmt.Printf("Generated Token %d: %s\n", i, token.Code)
fmt.Printf("Generated Token %d: %s\n", i, token)
}

// One more token that we will tamper with
token, _ := bucket.NewToken(4)
fmt.Printf("Generated Token 9: %s\n", token.Code)
token.Code = "_" + token.Code[1:7] + "_"
fmt.Printf("Generated Token 9: %s\n", token)
token = "_" + token[1:7] + "_"

// Find the closest match for the faulty token
match, distance := bucket.Resolve(token.Code)
fmt.Printf("Best match for '%s' is token '%s' with distance %d\n", token.Code, match.Code, distance)
match, distance := bucket.Resolve(token)
fmt.Printf("Best match for '%s' is token '%s' with distance %d\n", token, match, distance)
}
45 changes: 18 additions & 27 deletions toktok.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,12 @@ import (
"github.com/xrash/smetrics"
)

type Token struct {
Code string
}

// Bucket tracks all the generated tokens and lets you create new, unique tokens
type Bucket struct {
length uint
runes []rune

tokens map[string]Token
tokens map[string]bool
tries []uint64

sync.RWMutex
Expand All @@ -47,27 +43,24 @@ func NewBucketWithRunes(tokenLength uint, runes string) (Bucket, error) {
return Bucket{
length: tokenLength,
runes: []rune(runes),
tokens: make(map[string]Token),
tokens: make(map[string]bool),
}, nil
}

// LoadTokens adds previously generated tokens to the Bucket
func (bucket *Bucket) LoadTokens(tokens []string) {
for _, v := range tokens {
token := Token{
Code: v,
}
bucket.tokens[token.Code] = token
bucket.tokens[v] = true
}
}

// NewToken returns a new token with a minimal safety distance to all other existing tokens
func (bucket *Bucket) NewToken(distance int) (Token, error) {
func (bucket *Bucket) NewToken(distance int) (string, error) {
if distance < 1 {
return Token{}, ErrDistanceTooSmall
return "", ErrDistanceTooSmall
}
if bucket.EstimatedFillPercentage() > 95.0 {
return Token{}, ErrTokenSpaceExhausted
return "", ErrTokenSpaceExhausted
}

bucket.Lock()
Expand All @@ -80,8 +73,8 @@ func (bucket *Bucket) NewToken(distance int) (Token, error) {
c = GenerateToken(bucket.length, bucket.runes)

dupe := false
for _, token := range bucket.tokens {
if hd := smetrics.WagnerFischer(c, token.Code, 1, 1, 2); hd <= distance {
for token, _ := range bucket.tokens {
if hd := smetrics.WagnerFischer(c, token, 1, 1, 2); hd <= distance {
dupe = true
break
}
Expand All @@ -90,42 +83,40 @@ func (bucket *Bucket) NewToken(distance int) (Token, error) {
break
}
if i > 100 {
return Token{}, ErrTokenSpaceExhausted
return "", ErrTokenSpaceExhausted
}
}

token := Token{
Code: c,
}
bucket.tokens[token.Code] = token
bucket.tokens[c] = true

bucket.tries = append(bucket.tries, uint64(i))
if len(bucket.tries) > 5000 {
bucket.tries = bucket.tries[1:]
}

return token, nil
return c, nil
}

// Resolve tries to find the matching original token for a potentially corrupted token
func (bucket *Bucket) Resolve(code string) (Token, int) {
func (bucket *Bucket) Resolve(code string) (string, int) {
distance := 65536

bucket.RLock()
defer bucket.RUnlock()

// try to find a perfect match first
t, ok := bucket.tokens[code]
_, ok := bucket.tokens[code]
if ok {
return t, 0
return code, 0
}

var t string
// find the closest match
for _, token := range bucket.tokens {
if hd := smetrics.WagnerFischer(code, token.Code, 1, 1, 2); hd <= distance {
for token, _ := range bucket.tokens {
if hd := smetrics.WagnerFischer(code, token, 1, 1, 2); hd <= distance {
if hd == distance {
// duplicate distance, ignore the previous result as it's not unique enough
t = Token{}
t = ""
} else {
t = token
distance = hd
Expand Down
27 changes: 13 additions & 14 deletions toktok_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ func TestCodeGen(t *testing.T) {
if err != nil {
t.Errorf("Unexpected error %v", err)
}
if len(tok.Code) != int(length) {
t.Errorf("Wrong token length, expected %d, got %d", length, len(tok.Code))
if len(tok) != int(length) {
t.Errorf("Wrong token length, expected %d, got %d", length, len(tok))
}
}

Expand All @@ -46,8 +46,8 @@ func TestCodeLoad(t *testing.T) {
t.Errorf("Expected Count() to return 2, got %d", bucket.Count())
}
tok, _ := bucket.Resolve(code1)
if tok.Code != code1 {
t.Errorf("Expected Token '%s', got '%s'", code1, tok.Code)
if tok != code1 {
t.Errorf("Expected Token '%s', got '%s'", code1, tok)
}
}

Expand All @@ -72,7 +72,7 @@ func TestCodeError(t *testing.T) {
func TestCodeResolve(t *testing.T) {
bucket, _ := NewBucket(8)

var tok Token
var tok string
for i := 0; i < 32; i++ {
gtok, err := bucket.NewToken(4)
if err != nil {
Expand All @@ -83,7 +83,7 @@ func TestCodeResolve(t *testing.T) {
}
}

ntok, dist := bucket.Resolve(tok.Code)
ntok, dist := bucket.Resolve(tok)
if ntok != tok {
t.Errorf("Token mismatch, expected %v, got %v", tok, ntok)
}
Expand All @@ -95,8 +95,7 @@ func TestCodeResolve(t *testing.T) {
func TestCodeFaultyResolve(t *testing.T) {
bucket, _ := NewBucket(8)

var tok Token
var ttok Token
var tok, ttok string
for i := 0; i < 32; i++ {
gtok, err := bucket.NewToken(4)
if err != nil {
Expand All @@ -109,9 +108,9 @@ func TestCodeFaultyResolve(t *testing.T) {
}

// replace char in token
ttok.Code = " " + ttok.Code[1:]
ttok = " " + ttok[1:]

ntok, dist := bucket.Resolve(ttok.Code)
ntok, dist := bucket.Resolve(ttok)
if ntok != tok {
t.Errorf("Token mismatch, expected %v, got %v", tok, ntok)
}
Expand All @@ -120,9 +119,9 @@ func TestCodeFaultyResolve(t *testing.T) {
}

// insert char in token
ttok.Code = tok.Code + " "
ttok = tok + " "

ntok, dist = bucket.Resolve(ttok.Code)
ntok, dist = bucket.Resolve(ttok)
if ntok != tok {
t.Errorf("Token mismatch, expected %v, got %v", tok, ntok)
}
Expand All @@ -131,9 +130,9 @@ func TestCodeFaultyResolve(t *testing.T) {
}

// remove char in token
ttok.Code = tok.Code[1:]
ttok = tok[1:]

ntok, dist = bucket.Resolve(ttok.Code)
ntok, dist = bucket.Resolve(ttok)
if ntok != tok {
t.Errorf("Token mismatch, expected %v, got %v", tok, ntok)
}
Expand Down

0 comments on commit e31a6c5

Please sign in to comment.