fix(wpcarro/ynab): Remove .skip-subtree
**TL;DR:** - Delete half-baked packaging attempts (`job.nix`, `token.nix`). - Ensure golang code compiles. - Some "packages" were being treated like "programs" presumably for debugging/testing purposes back when I was working on this. Make those behave like libraries. - Remove stale imports. - Fix syntax errors. - Miscellaneous other chores. - Drop `shell.nix` and `use_nix` directive. Change-Id: I63c275680bac55a3cad3b9cb48d51cdc431fbe48 Reviewed-on: https://cl.tvl.fyi/c/depot/+/7318 Autosubmit: wpcarro <wpcarro@gmail.com> Tested-by: BuildkiteCI Reviewed-by: wpcarro <wpcarro@gmail.com>
This commit is contained in:
parent
982022826d
commit
d36aaeb967
11 changed files with 33 additions and 118 deletions
|
@ -1,5 +1,5 @@
|
||||||
source_up
|
source_up
|
||||||
use_nix
|
|
||||||
# TODO(wpcarro): Prefer age-nix solution if possible.
|
# TODO(wpcarro): Prefer age-nix solution if possible.
|
||||||
export monzo_client_id="$(jq -j '.monzo | .clientId' < $WPCARRO/secrets.json)"
|
export monzo_client_id="$(jq -j '.monzo | .clientId' < $WPCARRO/secrets.json)"
|
||||||
export monzo_client_secret="$(jq -j '.monzo | .clientSecret' < $WPCARRO/secrets.json)"
|
export monzo_client_secret="$(jq -j '.monzo | .clientSecret' < $WPCARRO/secrets.json)"
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
Subdirectories of this folder should not be imported since they are
|
|
||||||
internal to buildGo.nix and incompatible with readTree.
|
|
|
@ -1,15 +0,0 @@
|
||||||
{ depot, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
inherit (depot.users.wpcarro) gopkgs;
|
|
||||||
in
|
|
||||||
depot.nix.buildGo.program {
|
|
||||||
name = "job";
|
|
||||||
srcs = [
|
|
||||||
./main.go
|
|
||||||
];
|
|
||||||
deps = with gopkgs; [
|
|
||||||
kv
|
|
||||||
utils
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -10,8 +10,11 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"monzoClient"
|
||||||
"monzoSerde"
|
"monzoSerde"
|
||||||
"os"
|
"os"
|
||||||
|
"ynabClient"
|
||||||
|
"ynabSerde"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -34,11 +37,12 @@ func toYnab(tx monzoSerde.Transaction) ynabSerde.Transaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
monzo := monzoClient.Create()
|
||||||
txs := monzo.TransactionsLast24Hours()
|
txs := monzo.TransactionsLast24Hours()
|
||||||
var ynabTxs []ynabSerde.Transaction
|
var ynabTxs []ynabSerde.Transaction
|
||||||
for tx := range txs {
|
for _, tx := range txs {
|
||||||
append(ynabTxs, toYnab(tx))
|
ynabTxs = append(ynabTxs, toYnab(tx))
|
||||||
}
|
}
|
||||||
ynab.PostTransactions(ynabTxs)
|
ynabClient.PostTransactions(ynabTxs)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ func Create() *Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a slice of transactions from the last 24 hours.
|
// Returns a slice of transactions from the last 24 hours.
|
||||||
func (c *Client) Transactions24Hours() []monzoSerde.Transaction {
|
func (c *Client) TransactionsLast24Hours() []monzoSerde.Transaction {
|
||||||
token := tokens.AccessToken()
|
token := tokens.GetState().AccessToken
|
||||||
form := url.Values{"account_id": {accountID}}
|
form := url.Values{"account_id": {accountID}}
|
||||||
client := http.Client{}
|
client := http.Client{}
|
||||||
req, _ := http.NewRequest("POST", "https://api.monzo.com/transactions",
|
req, _ := http.NewRequest("POST", "https://api.monzo.com/transactions",
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
// This package hosts the serialization and deserialization logic for all of the
|
// This package hosts the serialization and deserialization logic for all of the
|
||||||
// data types with which our application interacts from the Monzo API.
|
// data types with which our application interacts from the Monzo API.
|
||||||
package main
|
package monzoSerde
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -72,11 +70,3 @@ func deserializeTx(x string) (*Transaction, error) {
|
||||||
err := json.Unmarshal([]byte(x), target)
|
err := json.Unmarshal([]byte(x), target)
|
||||||
return target, err
|
return target, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
b, _ := ioutil.ReadFile("./fixture.json")
|
|
||||||
tx := string(b)
|
|
||||||
target, _ := deserializeTx(tx)
|
|
||||||
out, _ := serializeTx(target)
|
|
||||||
fmt.Println(out)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
{ pkgs, ... }:
|
|
||||||
|
|
||||||
pkgs.mkShell {
|
|
||||||
buildInputs = with pkgs; [
|
|
||||||
go
|
|
||||||
goimports
|
|
||||||
godef
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Creating a Tokens server to manage my access and refresh tokens. Keeping this
|
// Creating a Tokens server to manage my access and refresh tokens. Keeping this
|
||||||
// as a separate server allows me to develop and use the access tokens without
|
// as a separate server allows me to develop and use the access tokens without
|
||||||
// going through client authorization.
|
// going through client authorization.
|
||||||
package main
|
package tokens
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Dependencies
|
// Dependencies
|
||||||
|
@ -46,7 +46,7 @@ type setTokensRequest struct {
|
||||||
|
|
||||||
// This is our application state.
|
// This is our application state.
|
||||||
type state struct {
|
type state struct {
|
||||||
accessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
refreshToken string `json:"refresh_token"`
|
refreshToken string `json:"refresh_token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ func logTokens(access string, refresh string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (state *state) String() string {
|
func (state *state) String() string {
|
||||||
return fmt.Sprintf("state{\n\taccessToken: \"%s\",\n\trefreshToken: \"%s\"\n}\n", state.accessToken, state.refreshToken)
|
return fmt.Sprintf("state{\n\tAccessToken: \"%s\",\n\trefreshToken: \"%s\"\n}\n", state.AccessToken, state.refreshToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule a token refresh for `expiresIn` seconds using the provided
|
// Schedule a token refresh for `expiresIn` seconds using the provided
|
||||||
|
@ -104,10 +104,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...")
|
||||||
accessToken, refreshToken := refreshTokens(refreshToken)
|
AccessToken, refreshToken := refreshTokens(refreshToken)
|
||||||
log.Println("Successfully refreshed tokens.")
|
log.Println("Successfully refreshed tokens.")
|
||||||
logTokens(accessToken, refreshToken)
|
logTokens(AccessToken, refreshToken)
|
||||||
setState(accessToken, refreshToken)
|
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
|
||||||
|
@ -169,8 +169,8 @@ func handleInterrupts() {
|
||||||
go func() {
|
go func() {
|
||||||
sig := <-sigs
|
sig := <-sigs
|
||||||
log.Printf("Received signal to shutdown. %v\n", sig)
|
log.Printf("Received signal to shutdown. %v\n", sig)
|
||||||
state := getState()
|
state := GetState()
|
||||||
persistTokens(state.accessToken, state.refreshToken)
|
persistTokens(state.AccessToken, state.refreshToken)
|
||||||
done <- true
|
done <- true
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -179,25 +179,21 @@ func handleInterrupts() {
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set `accessToken` and `refreshToken` on application state.
|
// Set `AccessToken` and `refreshToken` on application state.
|
||||||
func setState(accessToken string, refreshToken string) {
|
func setState(AccessToken string, refreshToken string) {
|
||||||
msg := writeMsg{state{accessToken, refreshToken}, make(chan bool)}
|
msg := writeMsg{state{AccessToken, refreshToken}, make(chan bool)}
|
||||||
chans.writes <- msg
|
chans.writes <- msg
|
||||||
<-msg.sender
|
<-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)}
|
||||||
chans.reads <- msg
|
chans.reads <- msg
|
||||||
return <-msg.sender
|
return <-msg.sender
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
func StartServer() {
|
||||||
// Main
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Manage application state.
|
// Manage application state.
|
||||||
go func() {
|
go func() {
|
||||||
state := &state{}
|
state := &state{}
|
||||||
|
@ -215,7 +211,7 @@ func main() {
|
||||||
// As an attempt to maintain consistency between application
|
// As an attempt to maintain consistency between application
|
||||||
// state and persisted state, everytime we write to the
|
// state and persisted state, everytime we write to the
|
||||||
// application state, we will write to the store.
|
// application state, we will write to the store.
|
||||||
persistTokens(state.accessToken, state.refreshToken)
|
persistTokens(state.AccessToken, state.refreshToken)
|
||||||
msg.sender <- true
|
msg.sender <- true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +247,7 @@ func main() {
|
||||||
log.Fatal(http.ListenAndServe(":4242",
|
log.Fatal(http.ListenAndServe(":4242",
|
||||||
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
if req.URL.Path == "/refresh-tokens" && req.Method == "POST" {
|
if req.URL.Path == "/refresh-tokens" && req.Method == "POST" {
|
||||||
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" {
|
||||||
|
@ -273,7 +269,7 @@ func main() {
|
||||||
} else if req.URL.Path == "/state" && req.Method == "GET" {
|
} else if req.URL.Path == "/state" && req.Method == "GET" {
|
||||||
// TODO(wpcarro): Ensure that this returns serialized state.
|
// TODO(wpcarro): Ensure that this returns serialized state.
|
||||||
w.Header().Set("Content-type", "application/json")
|
w.Header().Set("Content-type", "application/json")
|
||||||
state := getState()
|
state := GetState()
|
||||||
payload, _ := json.Marshal(state)
|
payload, _ := json.Marshal(state)
|
||||||
io.WriteString(w, string(payload))
|
io.WriteString(w, string(payload))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
{ depot, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
inherit (depot.users.wpcarro) gopkgs;
|
|
||||||
|
|
||||||
auth = depot.nix.buildGo.package {
|
|
||||||
name = "auth";
|
|
||||||
srcs = [
|
|
||||||
./auth.go
|
|
||||||
];
|
|
||||||
deps = with gopkgs; [
|
|
||||||
utils
|
|
||||||
];
|
|
||||||
};
|
|
||||||
in
|
|
||||||
depot.nix.buildGo.program {
|
|
||||||
name = "token-server";
|
|
||||||
srcs = [
|
|
||||||
./tokens.go
|
|
||||||
];
|
|
||||||
deps = with gopkgs; [
|
|
||||||
kv
|
|
||||||
utils
|
|
||||||
auth
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,24 +1,9 @@
|
||||||
package client
|
package ynabClient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"serde"
|
"ynabSerde"
|
||||||
)
|
)
|
||||||
|
|
||||||
// // See requests.txt for more details.
|
// See requests.txt for more details.
|
||||||
// func PostTransactions(accountID string, txs []serde.Transaction{}) error {
|
func PostTransactions(txs []ynabSerde.Transaction) {
|
||||||
// return map[string]string{
|
}
|
||||||
// "transactions": [
|
|
||||||
// {
|
|
||||||
// "account_id": accountID,
|
|
||||||
// "date": "2019-12-30",
|
|
||||||
// "amount": 10000,
|
|
||||||
// "payee_name": "Richard Stallman",
|
|
||||||
// "memo": "Not so free software after all...",
|
|
||||||
// "cleared": "cleared",
|
|
||||||
// "approved": true,
|
|
||||||
// "flag_color": "red",
|
|
||||||
// "import_id": "xyz-123"
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
// This package hosts the serialization and deserialization logic for all of the
|
// This package hosts the serialization and deserialization logic for all of the
|
||||||
// data types with which our application interacts from the YNAB API.
|
// data types with which our application interacts from the YNAB API.
|
||||||
package main
|
package ynabSerde
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -43,10 +42,3 @@ func deserializeTx(x string) (*Transaction, error) {
|
||||||
err := json.Unmarshal([]byte(x), target)
|
err := json.Unmarshal([]byte(x), target)
|
||||||
return target, err
|
return target, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
target, _ := deserializeTx(tx)
|
|
||||||
out, _ := serializeTx(target)
|
|
||||||
fmt.Println(out)
|
|
||||||
fmt.Println(ynabOut)
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue