Auth works
This commit is contained in:
		
							parent
							
								
									7fc7b1889b
								
							
						
					
					
						commit
						4295811647
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +1,2 @@ | |||||||
| config.json | config.json | ||||||
|  | *.txt | ||||||
|  | |||||||
| @ -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_id": "XXXXXXXXXXXXXXXXXXXX", | ||||||
|     "github_client_secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", |     "github_client_secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", | ||||||
|     "github_redirect_uri": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" |     "github_redirect_uri": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" | ||||||
|  | |||||||
| @ -15,3 +15,7 @@ type ( | |||||||
| 		CreatedAt time.Time | 		CreatedAt time.Time | ||||||
| 	} | 	} | ||||||
| ) | ) | ||||||
|  | 
 | ||||||
|  | func UpdateToken(t *Token) { | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | |||||||
							
								
								
									
										56
									
								
								job/job.go
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								job/job.go
									
									
									
									
									
								
							| @ -4,35 +4,60 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | 	"code.google.com/p/go-uuid/uuid" | ||||||
|  | 
 | ||||||
| 	"github.com/fatih/structs" | 	"github.com/fatih/structs" | ||||||
| 	"github.com/localhots/empact/db" | 	"github.com/localhots/empact/task" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ( | type ( | ||||||
| 	Job struct { | 	Job struct { | ||||||
| 		Name    string | 		Name    string | ||||||
| 		actor   func(*db.Task) | 		actor   func(task.Tasker) | ||||||
| 		workers map[string]*worker | 		workers map[string]*worker | ||||||
| 		tasks   chan *db.Task | 		orders  chan struct{} // Currently shutdown only | ||||||
|  | 		tasks   chan task.Tasker | ||||||
| 		wg      sync.WaitGroup | 		wg      sync.WaitGroup | ||||||
| 	} | 	} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func New(name string, actor func()) *Job { | var ( | ||||||
| 	&Job{ | 	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, | 		Name:    name, | ||||||
| 		actor:   actor, | 		actor:   actor, | ||||||
| 		workers: make(map[string]*worker), | 		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 { | func (j *Job) Size() int { | ||||||
| 	return len(j.workers) | 	return len(j.workers) | ||||||
| } | } | ||||||
| @ -49,9 +74,8 @@ func (j *Job) Resize(n int) { | |||||||
| 	if del := n - len(j.workers); del > 0 { | 	if del := n - len(j.workers); del > 0 { | ||||||
| 		for i := 0; i < del; i++ { | 		for i := 0; i < del; i++ { | ||||||
| 			w := &worker{ | 			w := &worker{ | ||||||
| 				id:       newID(), | 				id:  uuid.New(), | ||||||
| 				job:      j, | 				job: j, | ||||||
| 				shutdown: make(<-chan struct{}, 1), |  | ||||||
| 			} | 			} | ||||||
| 			go w.workHard() | 			go w.workHard() | ||||||
| 			j.workers[w.id] = w | 			j.workers[w.id] = w | ||||||
| @ -59,7 +83,7 @@ func (j *Job) Resize(n int) { | |||||||
| 		j.wg.Add(del) | 		j.wg.Add(del) | ||||||
| 	} else { | 	} else { | ||||||
| 		for i := 0; i > del; i-- { | 		for i := 0; i > del; i-- { | ||||||
| 			j.shutdown <- struct{}{} | 			j.orders <- struct{}{} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,17 +1,17 @@ | |||||||
| package job | package job | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"code.google.com/p/go-uuid/uuid" | 	"github.com/localhots/empact/task" | ||||||
| 	"github.com/localhots/empact/db" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ( | type ( | ||||||
| 	worker struct { | 	worker struct { | ||||||
| 		id       string | 		id  string | ||||||
| 		job      *Job | 		job *Job | ||||||
| 		shutdown <-chan struct{} | 		wg  *sync.WaitGroup | ||||||
| 	} | 	} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -19,7 +19,7 @@ func (w *worker) workHard() { | |||||||
| 	defer w.wg.Done() | 	defer w.wg.Done() | ||||||
| 	for { | 	for { | ||||||
| 		select { | 		select { | ||||||
| 		case <-w.shutdown: | 		case <-w.job.orders: | ||||||
| 			return | 			return | ||||||
| 		case t := <-w.job.tasks: | 		case t := <-w.job.tasks: | ||||||
| 			w.perform(t) | 			w.perform(t) | ||||||
| @ -27,19 +27,17 @@ func (w *worker) workHard() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (w *worker) perform(t *db.Task) { | func (w *worker) perform(t task.Tasker) { | ||||||
| 	t.Worker = w.id | 	dt := t.T() | ||||||
| 	t.StartedAt = time.Now() | 	dt.Worker = w.id | ||||||
|  | 	dt.StartedAt = time.Now() | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		err := recover() | 		if err := recover(); err != nil { | ||||||
| 		t.Duration = time.Since(t.StartedAt).Nanoseconds() | 			// dt.Error = err.(string) | ||||||
| 		t.Error = err.String() | 		} | ||||||
| 		t.Save() | 		dt.Duration = time.Since(dt.StartedAt).Nanoseconds() | ||||||
|  | 		dt.Save() | ||||||
| 	}() | 	}() | ||||||
| 
 | 
 | ||||||
| 	w.job.actor(t) | 	w.job.actor(t) | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func newID() string { |  | ||||||
| 	return uuid.New() |  | ||||||
| } |  | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								main.go
									
									
									
									
									
										Normal 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() | ||||||
|  | } | ||||||
| @ -1,18 +1,14 @@ | |||||||
| package server | package server | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bytes" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io/ioutil" |  | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 
 | 
 | ||||||
| 	"github.com/localhots/empact/config" | 	"github.com/localhots/empact/config" | ||||||
| ) | 	"github.com/localhots/empact/db" | ||||||
| 
 | 	"github.com/localhots/empact/job" | ||||||
| const ( | 	"github.com/localhots/empact/task" | ||||||
| 	authURL        = "https://github.com/login/oauth/authorize" |  | ||||||
| 	accessTokenURL = "https://github.com/login/oauth/access_token" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func authSigninHandler(w http.ResponseWriter, r *http.Request) { | 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("client_id", config.C().ClientID) | ||||||
| 	params.Set("redirect_uri", config.C().RedirectURI) | 	params.Set("redirect_uri", config.C().RedirectURI) | ||||||
| 	params.Set("scope", "repo") | 	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) { | func authCallbackHandler(w http.ResponseWriter, r *http.Request) { | ||||||
| 	if r.FormValue("error") != "" { | 	if r.FormValue("error") != "" { | ||||||
| 		w.Write([]byte(r.FormValue("error_description"))) | 		w.Write([]byte(r.FormValue("error_description"))) | ||||||
| 	} else { | 	} else { | ||||||
| 		fmt.Println("Got code: ", r.FormValue("code")) | 		code := r.FormValue("code") | ||||||
| 		token := getAccessToken(r.FormValue("code")) | 		fmt.Println("Got code: ", code) | ||||||
| 		fmt.Println("Got access token: ", token) | 
 | ||||||
| 		w.Write([]byte(token)) | 		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") |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -1,11 +1,39 @@ | |||||||
| package server | package server | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"code.google.com/p/go-uuid/uuid" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	sessionCookie = "session_id" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Start() { | func Start() { | ||||||
|  | 	fmt.Println("Starting server at http://localhost:8080") | ||||||
|  | 	http.HandleFunc("/", sessionHandler) | ||||||
| 	http.HandleFunc("/auth/signin", authSigninHandler) | 	http.HandleFunc("/auth/signin", authSigninHandler) | ||||||
| 	http.HandleFunc("/auth/callback", authCallbackHandler) | 	http.HandleFunc("/auth/callback", authCallbackHandler) | ||||||
| 	http.ListenAndServe(":8080", nil) | 	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
									
								
							
							
						
						
									
										44
									
								
								task/access_token.go
									
									
									
									
									
										Normal 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") | ||||||
|  | } | ||||||
| @ -6,6 +6,13 @@ import ( | |||||||
| 	"github.com/localhots/empact/db" | 	"github.com/localhots/empact/db" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | type ( | ||||||
|  | 	Tasker interface { | ||||||
|  | 		Save() | ||||||
|  | 		T() *db.Task | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| func newGithubClient(token string) *github.Client { | func newGithubClient(token string) *github.Client { | ||||||
| 	trans := &oauth.Transport{ | 	trans := &oauth.Transport{ | ||||||
| 		Token: &oauth.Token{AccessToken: token}, | 		Token: &oauth.Token{AccessToken: token}, | ||||||
|  | |||||||
| @ -7,11 +7,12 @@ import ( | |||||||
| type ( | type ( | ||||||
| 	SyncContribTask struct { | 	SyncContribTask struct { | ||||||
| 		Repo string | 		Repo string | ||||||
| 		db.Task | 		*db.Task | ||||||
| 	} | 	} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func SyncContrib(t SyncContribTask) { | func SyncContrib(tk Tasker) { | ||||||
|  | 	t := tk.(*SyncContribTask) | ||||||
| 	client := newGithubClient(t.Token) | 	client := newGithubClient(t.Token) | ||||||
| 	contribs, resp, err := client.Repositories.ListContributorsStats(t.Owner, t.Repo) | 	contribs, resp, err := client.Repositories.ListContributorsStats(t.Owner, t.Repo) | ||||||
| 	saveResponseMeta(t.Token, resp) | 	saveResponseMeta(t.Token, resp) | ||||||
|  | |||||||
| @ -7,13 +7,13 @@ import ( | |||||||
| 
 | 
 | ||||||
| type ( | type ( | ||||||
| 	SyncReposTask struct { | 	SyncReposTask struct { | ||||||
| 		db.Task | 		*db.Task | ||||||
| 	} | 	} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func SyncRepos(t SyncReposTask) { | func SyncRepos(tk Tasker) { | ||||||
| 	client := newGithubClient(token) | 	t := tk.(*SyncReposTask) | ||||||
| 	names := []string{} | 	client := newGithubClient(t.Token) | ||||||
| 	opt := &github.RepositoryListByOrgOptions{ | 	opt := &github.RepositoryListByOrgOptions{ | ||||||
| 		ListOptions: github.ListOptions{}, | 		ListOptions: github.ListOptions{}, | ||||||
| 	} | 	} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user