Forked from christianchristensen/twitterfindname.go
Last active
August 29, 2015 14:05
-
-
Save umayr/02c5c5e47161d1fcd13c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package twitterfindname | |
import ( | |
"encoding/json" | |
"fmt" | |
"io/ioutil" | |
"net/http" | |
"strings" | |
) | |
type HttpResponse struct { | |
url string | |
name string | |
nameresp UsernameLookup | |
valid bool | |
response *http.Response | |
err error | |
} | |
type UsernameLookup struct { | |
// Reason: for twitter username: available, taken | |
Reason string `json:"reason"` | |
// Message: Message about selected username | |
Message string `json:"msg"` | |
// Valid: Is this a valid username? | |
Valid bool `json:"valid"` | |
// Description: More info about the chosen username | |
Description string `json:"desc"` | |
} | |
// Given a JSON string return if the serialized data says is Available | |
func TwitterNameAvailable(s string) (bool, UsernameLookup, error) { | |
// See docs: http://golang.org/pkg/encoding/json/#example_Decoder | |
dec := json.NewDecoder(strings.NewReader(s)) | |
var m UsernameLookup | |
if err := dec.Decode(&m); err != nil { | |
return false, UsernameLookup{}, err | |
} | |
return m.Valid, m, nil | |
} | |
func FindTwitterUsernames() { | |
names := generate3letterUsernames() | |
// Split the number of concurrent dispatches into chunks | |
// This was necessary on my local machine b/c dispatching all resulted in: | |
// panic: runtime error: invalid memory address or nil pointer dereference | |
// [signal 0xb code=0x1 addr=0x38 pc=0x26399] | |
// goroutine 257 [running]:... | |
// Note: ^ interesting that it's ~256-ish... | |
splitby := 200 | |
splitnames := names | |
for i := 0; i*splitby < len(names); i++ { | |
if (i+1)*splitby > len(names) { | |
splitnames = names[(i * splitby):len(names)] | |
} else { | |
splitnames = names[(i * splitby):((i + 1) * splitby)] | |
} | |
results := asyncHttpGetsValidate(splitnames) | |
for _ = range splitnames { | |
result := <-results | |
fmt.Printf("%t: %s - %s\n", result.valid, result.name, result.nameresp) | |
} | |
} | |
} | |
func generate2letterUsernames() []string { | |
validchars := "0123456789abcdefghijklmnopqrstuvwxyz_" | |
var result []string | |
for _, firstchar := range validchars { | |
for _, secondchar := range validchars { | |
result = append(result, string(firstchar)+string(secondchar)) | |
} | |
} | |
return result | |
} | |
func generate3letterUsernames() []string { | |
validchars := "0123456789abcdefghijklmnopqrstuvwxyz_" | |
var result []string | |
for _, firstchar := range validchars { | |
for _, secondchar := range validchars { | |
for _, thirdchar := range validchars { | |
result = append(result, string(firstchar)+string(secondchar)+string(thirdchar)) | |
} | |
} | |
} | |
return result | |
} | |
func asyncHttpGetsValidate(names []string) <-chan *HttpResponse { | |
// Originally from: https://gist.github.com/4013851 | |
ch := make(chan *HttpResponse, len(names)) // buffered | |
for _, name := range names { | |
go func(name string) { | |
// Lookup if the twitter username is available | |
url := "https://twitter.com/users/username_available?username=" + name | |
fmt.Printf("Fetching username: %s \n", name) | |
resp, err := http.Get(url) | |
body, err := ioutil.ReadAll(resp.Body) | |
valid, usernamejson, err := TwitterNameAvailable(string(body)) | |
resp.Body.Close() | |
ch <- &HttpResponse{url, name, usernamejson, valid, resp, err} | |
}(name) | |
} | |
return ch | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package twitterfindname | |
import "testing" | |
func TestTwitterNameAvailable(t *testing.T) { | |
var tests = []struct { | |
valid bool | |
name, response string | |
}{ | |
{false, "☃", `{"reason":"improper_format","msg":"Only use letters, numbers and '_'","valid":false,"desc":"Your username can only contain letters, numbers and '_'"}`}, | |
{true, "thisnameisnottaken", `{"reason":"available","msg":"Available!","valid":true,"desc":"Available!"}`}, | |
{false, "a", `{"reason":"taken","msg":"Username has already been taken","valid":false,"desc":"That username has been taken. Please choose another."}`}, | |
} | |
for _, c := range tests { | |
valid, _, _ := TwitterNameAvailable(c.response) | |
if valid != c.valid { | |
t.Errorf("TwitterNameAvailable(%q) should be %t", c.name, c.valid) | |
} | |
} | |
} | |
func TestFindTwitterUsername(t *testing.T) { | |
if len(generate2letterUsernames()) != 1369 { | |
t.Errorf("generate2letterUsernames") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment