Refactor token server initialization
- Move state "gen server" to the top of main/0 - Initialize it as empty - Ensure that persistTokens/2 is called whenever the state changes - Support setState/2 (similar in spirit to getState/0)
This commit is contained in:
parent
d35eb5c8f9
commit
bd88f40224
1 changed files with 42 additions and 30 deletions
|
@ -56,6 +56,7 @@ type readMsg struct {
|
||||||
|
|
||||||
type writeMsg struct {
|
type writeMsg struct {
|
||||||
state state
|
state state
|
||||||
|
sender chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type channels struct {
|
type channels struct {
|
||||||
|
@ -102,10 +103,10 @@ func scheduleTokenRefresh(expiresIn int, refreshToken string) {
|
||||||
log.Printf("Scheduling token refresh for %v\n", timestamp)
|
log.Printf("Scheduling token refresh for %v\n", timestamp)
|
||||||
time.Sleep(duration)
|
time.Sleep(duration)
|
||||||
log.Println("Refreshing tokens now...")
|
log.Println("Refreshing tokens now...")
|
||||||
access, refresh := refreshTokens(refreshToken)
|
accessToken, refreshToken := refreshTokens(refreshToken)
|
||||||
log.Println("Successfully refreshed tokens.")
|
log.Println("Successfully refreshed tokens.")
|
||||||
logTokens(access, refresh)
|
logTokens(accessToken, refreshToken)
|
||||||
chans.writes <- writeMsg{state{access, refresh}}
|
setState(accessToken, refreshToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exchange existing credentials for a new access token and `refreshToken`. Also
|
// Exchange existing credentials for a new access token and `refreshToken`. Also
|
||||||
|
@ -177,6 +178,13 @@ func handleInterrupts() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set `accessToken` and `refreshToken` on application state.
|
||||||
|
func setState(accessToken string, refreshToken string) {
|
||||||
|
msg := writeMsg{state{accessToken, refreshToken}, make(chan bool)}
|
||||||
|
chans.writes <- msg
|
||||||
|
<-msg.sender
|
||||||
|
}
|
||||||
|
|
||||||
// Return our application state.
|
// Return our application state.
|
||||||
func getState() state {
|
func getState() state {
|
||||||
msg := readMsg{make(chan state)}
|
msg := readMsg{make(chan state)}
|
||||||
|
@ -189,24 +197,9 @@ func getState() state {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Retrieve cached tokens from store.
|
|
||||||
accessToken := fmt.Sprintf("%v", kv.Get("monzoAccessToken"))
|
|
||||||
refreshToken := fmt.Sprintf("%v", kv.Get("monzoRefreshToken"))
|
|
||||||
|
|
||||||
log.Println("Attempting to retrieve cached credentials...")
|
|
||||||
logTokens(accessToken, refreshToken)
|
|
||||||
|
|
||||||
if accessToken == "" || refreshToken == "" {
|
|
||||||
log.Println("Cached credentials are absent. Authorizing client...")
|
|
||||||
authCode := auth.GetAuthCode(monzoClientId)
|
|
||||||
tokens := auth.GetTokensFromAuthCode(authCode, monzoClientId, monzoClientSecret)
|
|
||||||
accessToken, refreshToken = tokens.AccessToken, tokens.RefreshToken
|
|
||||||
go persistTokens(accessToken, refreshToken)
|
|
||||||
go scheduleTokenRefresh(tokens.ExpiresIn, refreshToken)
|
|
||||||
}
|
|
||||||
// Manage application state.
|
// Manage application state.
|
||||||
go func() {
|
go func() {
|
||||||
state := &state{accessToken, refreshToken}
|
state := &state{}
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case msg := <-chans.reads:
|
case msg := <-chans.reads:
|
||||||
|
@ -218,18 +211,39 @@ func main() {
|
||||||
log.Printf("Old: %s\n", state)
|
log.Printf("Old: %s\n", state)
|
||||||
*state = msg.state
|
*state = msg.state
|
||||||
log.Printf("New: %s\n", state)
|
log.Printf("New: %s\n", state)
|
||||||
|
// As an attempt to maintain consistency between application
|
||||||
|
// state and persisted state, everytime we write to the
|
||||||
|
// application state, we will write to the store.
|
||||||
|
persistTokens(state.accessToken, state.refreshToken)
|
||||||
|
msg.sender <- true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Gracefully shutdown.
|
// Retrieve cached tokens from store.
|
||||||
go handleInterrupts()
|
accessToken := fmt.Sprintf("%v", kv.Get("monzoAccessToken"))
|
||||||
|
refreshToken := fmt.Sprintf("%v", kv.Get("monzoRefreshToken"))
|
||||||
|
|
||||||
|
log.Println("Attempting to retrieve cached credentials...")
|
||||||
|
logTokens(accessToken, refreshToken)
|
||||||
|
|
||||||
|
if accessToken == "" || refreshToken == "" {
|
||||||
|
log.Println("Cached credentials are absent. Authorizing client...")
|
||||||
|
authCode := auth.GetAuthCode(monzoClientId)
|
||||||
|
tokens := auth.GetTokensFromAuthCode(authCode, monzoClientId, monzoClientSecret)
|
||||||
|
setState(tokens.AccessToken, tokens.RefreshToken)
|
||||||
|
go scheduleTokenRefresh(tokens.ExpiresIn, tokens.RefreshToken)
|
||||||
|
} else {
|
||||||
|
setState(accessToken, refreshToken)
|
||||||
// If we have tokens, they may be expiring soon. We don't know because
|
// If we have tokens, they may be expiring soon. We don't know because
|
||||||
// we aren't storing the expiration timestamp in the state or in the
|
// we aren't storing the expiration timestamp in the state or in the
|
||||||
// store. Until we have that information, and to be safe, let's refresh
|
// store. Until we have that information, and to be safe, let's refresh
|
||||||
// the tokens.
|
// the tokens.
|
||||||
scheduleTokenRefresh(0, refreshToken)
|
go scheduleTokenRefresh(0, refreshToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gracefully handle shutdowns.
|
||||||
|
go handleInterrupts()
|
||||||
|
|
||||||
// Listen to inbound requests.
|
// Listen to inbound requests.
|
||||||
fmt.Println("Listening on http://localhost:4242 ...")
|
fmt.Println("Listening on http://localhost:4242 ...")
|
||||||
|
@ -239,7 +253,6 @@ func main() {
|
||||||
state := getState()
|
state := getState()
|
||||||
go scheduleTokenRefresh(0, state.refreshToken)
|
go scheduleTokenRefresh(0, state.refreshToken)
|
||||||
fmt.Fprintf(w, "Done.")
|
fmt.Fprintf(w, "Done.")
|
||||||
|
|
||||||
} else if req.URL.Path == "/set-tokens" && req.Method == "POST" {
|
} else if req.URL.Path == "/set-tokens" && req.Method == "POST" {
|
||||||
// Parse
|
// Parse
|
||||||
payload := &setTokensRequest{}
|
payload := &setTokensRequest{}
|
||||||
|
@ -249,8 +262,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update application state
|
// Update application state
|
||||||
msg := writeMsg{state{payload.AccessToken, payload.RefreshToken}}
|
setState(payload.AccessToken, payload.RefreshToken)
|
||||||
chans.writes <- msg
|
|
||||||
|
|
||||||
// Refresh tokens
|
// Refresh tokens
|
||||||
go scheduleTokenRefresh(payload.ExpiresIn, payload.RefreshToken)
|
go scheduleTokenRefresh(payload.ExpiresIn, payload.RefreshToken)
|
||||||
|
|
Loading…
Reference in a new issue