Auth works
This commit is contained in:
parent
7fc7b1889b
commit
4295811647
|
@ -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()
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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…
Reference in New Issue