1
0
Fork 0

Auth works

This commit is contained in:
Gregory Eremin 2015-03-05 19:57:36 +07:00
parent 7fc7b1889b
commit 4295811647
12 changed files with 185 additions and 74 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
config.json
*.txt

View File

@ -1,4 +1,8 @@
{
"app_domain": "localhost",
"database_uri": "root@/empact",
"github_auth_url": "https://github.com/login/oauth/authorize",
"github_access_token_url": "https://github.com/login/oauth/access_token",
"github_client_id": "XXXXXXXXXXXXXXXXXXXX",
"github_client_secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"github_redirect_uri": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

View File

@ -15,3 +15,7 @@ type (
CreatedAt time.Time
}
)
func UpdateToken(t *Token) {
}

View File

@ -4,35 +4,60 @@ import (
"sync"
"time"
"code.google.com/p/go-uuid/uuid"
"github.com/fatih/structs"
"github.com/localhots/empact/db"
"github.com/localhots/empact/task"
)
type (
Job struct {
Name string
actor func(*db.Task)
actor func(task.Tasker)
workers map[string]*worker
tasks chan *db.Task
orders chan struct{} // Currently shutdown only
tasks chan task.Tasker
wg sync.WaitGroup
}
)
func New(name string, actor func()) *Job {
&Job{
var (
jobs = map[string]*Job{}
)
func Enqueue(t task.Tasker) {
dt := t.T()
dt.Job = structs.Name(t)
dt.CreatedAt = time.Now()
j, ok := jobs[dt.Job]
if !ok {
switch dt.Job {
case "FetchAccessTokenTask":
j = New(dt.Job, task.FetchAccessToken)
case "SyncContribTask":
j = New(dt.Job, task.SyncContrib)
case "SyncReposTask":
j = New(dt.Job, task.SyncRepos)
default:
panic("Unknown task: " + dt.Job)
}
jobs[dt.Job] = j
j.Resize(1)
}
j.tasks <- t
}
func New(name string, actor func(task.Tasker)) *Job {
return &Job{
Name: name,
actor: actor,
workers: make(map[string]*worker),
tasks: make(chan *db.Task, 1000),
orders: make(chan struct{}),
tasks: make(chan task.Tasker, 1000),
}
}
func (j *Job) Perform(t *db.Task) {
t.Job = structs.Name(t)
t.CreatedAt = time.Now()
j.tasks <- t
}
func (j *Job) Size() int {
return len(j.workers)
}
@ -49,9 +74,8 @@ func (j *Job) Resize(n int) {
if del := n - len(j.workers); del > 0 {
for i := 0; i < del; i++ {
w := &worker{
id: newID(),
job: j,
shutdown: make(<-chan struct{}, 1),
id: uuid.New(),
job: j,
}
go w.workHard()
j.workers[w.id] = w
@ -59,7 +83,7 @@ func (j *Job) Resize(n int) {
j.wg.Add(del)
} else {
for i := 0; i > del; i-- {
j.shutdown <- struct{}{}
j.orders <- struct{}{}
}
}
}

View File

@ -1,17 +1,17 @@
package job
import (
"sync"
"time"
"code.google.com/p/go-uuid/uuid"
"github.com/localhots/empact/db"
"github.com/localhots/empact/task"
)
type (
worker struct {
id string
job *Job
shutdown <-chan struct{}
id string
job *Job
wg *sync.WaitGroup
}
)
@ -19,7 +19,7 @@ func (w *worker) workHard() {
defer w.wg.Done()
for {
select {
case <-w.shutdown:
case <-w.job.orders:
return
case t := <-w.job.tasks:
w.perform(t)
@ -27,19 +27,17 @@ func (w *worker) workHard() {
}
}
func (w *worker) perform(t *db.Task) {
t.Worker = w.id
t.StartedAt = time.Now()
func (w *worker) perform(t task.Tasker) {
dt := t.T()
dt.Worker = w.id
dt.StartedAt = time.Now()
defer func() {
err := recover()
t.Duration = time.Since(t.StartedAt).Nanoseconds()
t.Error = err.String()
t.Save()
if err := recover(); err != nil {
// dt.Error = err.(string)
}
dt.Duration = time.Since(dt.StartedAt).Nanoseconds()
dt.Save()
}()
w.job.actor(t)
}
func newID() string {
return uuid.New()
}

15
main.go Normal file
View File

@ -0,0 +1,15 @@
package main
import (
"github.com/localhots/empact/config"
"github.com/localhots/empact/db"
"github.com/localhots/empact/server"
)
func main() {
if err := db.Connect(config.C().DatabaseURI); err != nil {
panic(err)
}
server.Start()
}

View File

@ -1,18 +1,14 @@
package server
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"github.com/localhots/empact/config"
)
const (
authURL = "https://github.com/login/oauth/authorize"
accessTokenURL = "https://github.com/login/oauth/access_token"
"github.com/localhots/empact/db"
"github.com/localhots/empact/job"
"github.com/localhots/empact/task"
)
func authSigninHandler(w http.ResponseWriter, r *http.Request) {
@ -20,39 +16,28 @@ func authSigninHandler(w http.ResponseWriter, r *http.Request) {
params.Set("client_id", config.C().ClientID)
params.Set("redirect_uri", config.C().RedirectURI)
params.Set("scope", "repo")
http.Redirect(w, r, authURL+"?"+params.Encode(), 302)
http.Redirect(w, r, config.C().AuthURL+"?"+params.Encode(), 302)
}
func authCallbackHandler(w http.ResponseWriter, r *http.Request) {
if r.FormValue("error") != "" {
w.Write([]byte(r.FormValue("error_description")))
} else {
fmt.Println("Got code: ", r.FormValue("code"))
token := getAccessToken(r.FormValue("code"))
fmt.Println("Got access token: ", token)
w.Write([]byte(token))
code := r.FormValue("code")
fmt.Println("Got code: ", code)
res := make(chan string)
job.Enqueue(&task.FetchAccessTokenTask{
Code: code,
Result: res,
Task: &db.Task{},
})
if token, ok := <-res; ok {
fmt.Println("Got access token: ", token)
w.Write([]byte(token))
} else {
panic("Failed to fetch token")
}
}
}
func getAccessToken(code string) string {
payload := url.Values{}
payload.Set("client_id", config.C().ClientID)
payload.Set("client_secret", config.C().ClientSecret)
payload.Set("code", code)
payload.Set("redirect_uri", config.C().RedirectURI)
buf := bytes.NewBuffer([]byte(payload.Encode()))
resp, err := http.Post(accessTokenURL, "application/x-www-form-urlencoded", buf)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
pairs, _ := url.ParseQuery(string(body))
return pairs.Get("access_token")
}

View File

@ -1,11 +1,39 @@
package server
import (
"fmt"
"net/http"
"time"
"code.google.com/p/go-uuid/uuid"
)
const (
sessionCookie = "session_id"
)
func Start() {
fmt.Println("Starting server at http://localhost:8080")
http.HandleFunc("/", sessionHandler)
http.HandleFunc("/auth/signin", authSigninHandler)
http.HandleFunc("/auth/callback", authCallbackHandler)
http.ListenAndServe(":8080", nil)
}
func sessionHandler(w http.ResponseWriter, r *http.Request) {
if cook, err := r.Cookie(sessionCookie); err != nil {
cook = &http.Cookie{
Name: sessionCookie,
Value: uuid.New(),
Path: "/",
Expires: time.Now().Add(365 * 24 * time.Hour),
HttpOnly: true,
}
http.SetCookie(w, cook)
}
}
func sessionID(r *http.Request) string {
cook, _ := r.Cookie(sessionCookie)
return cook.Value
}

44
task/access_token.go Normal file
View File

@ -0,0 +1,44 @@
package task
import (
"bytes"
"io/ioutil"
"net/http"
"net/url"
"github.com/localhots/empact/config"
"github.com/localhots/empact/db"
)
type (
FetchAccessTokenTask struct {
Code string
Result chan string
*db.Task
}
)
func FetchAccessToken(tk Tasker) {
t := tk.(*FetchAccessTokenTask)
payload := url.Values{}
payload.Set("client_id", config.C().ClientID)
payload.Set("client_secret", config.C().ClientSecret)
payload.Set("code", t.Code)
payload.Set("redirect_uri", config.C().RedirectURI)
buf := bytes.NewBuffer([]byte(payload.Encode()))
resp, err := http.Post(config.C().AccessTokenURL, "application/x-www-form-urlencoded", buf)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
pairs, _ := url.ParseQuery(string(body))
t.Result <- pairs.Get("access_token")
}

View File

@ -6,6 +6,13 @@ import (
"github.com/localhots/empact/db"
)
type (
Tasker interface {
Save()
T() *db.Task
}
)
func newGithubClient(token string) *github.Client {
trans := &oauth.Transport{
Token: &oauth.Token{AccessToken: token},

View File

@ -7,11 +7,12 @@ import (
type (
SyncContribTask struct {
Repo string
db.Task
*db.Task
}
)
func SyncContrib(t SyncContribTask) {
func SyncContrib(tk Tasker) {
t := tk.(*SyncContribTask)
client := newGithubClient(t.Token)
contribs, resp, err := client.Repositories.ListContributorsStats(t.Owner, t.Repo)
saveResponseMeta(t.Token, resp)

View File

@ -7,13 +7,13 @@ import (
type (
SyncReposTask struct {
db.Task
*db.Task
}
)
func SyncRepos(t SyncReposTask) {
client := newGithubClient(token)
names := []string{}
func SyncRepos(tk Tasker) {
t := tk.(*SyncReposTask)
client := newGithubClient(t.Token)
opt := &github.RepositoryListByOrgOptions{
ListOptions: github.ListOptions{},
}