Skip to content

Commit

Permalink
Merge pull request #10 from ThreeDotsLabs/region-select
Browse files Browse the repository at this point in the history
Add --region flag
  • Loading branch information
m110 committed Feb 23, 2024
2 parents d56cb8a + bf58f27 commit e3d5bd8
Show file tree
Hide file tree
Showing 10 changed files with 454 additions and 208 deletions.
39 changes: 39 additions & 0 deletions README.md
@@ -0,0 +1,39 @@
# tdl

This is the `tdl` CLI tool used for running the interactive trainings on the [Three Dots Labs Academy](https://academy.threedots.tech).

## Install

### Script (macOS, Linux) - recommended

```sh
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/ThreeDotsLabs/cli/master/install.sh)" -- -b /usr/local/bin
```

### Script (Windows)

Install to your home directory:

```sh
iwr https://raw.githubusercontent.com/ThreeDotsLabs/cli/master/install.ps1 -useb | iex
```

Or install in any chosen path:

```sh
$env:TDL_INSTALL = 'bin\'
iwr https://raw.githubusercontent.com/ThreeDotsLabs/cli/master/install.ps1 -useb | iex
```

### Binaries

Download the latest binary from GitHub and move it to a directory in your `$PATH`.

[See Releases](https://github.com/ThreeDotsLabs/cli/releases)

### From source

```sh
go install github.com/ThreeDotsLabs/cli/tdl@latest
```

15 changes: 15 additions & 0 deletions internal/config.go
@@ -0,0 +1,15 @@
package internal

import (
"os"
"path/filepath"
)

func GlobalConfigDir() string {
userConfigDir, err := os.UserConfigDir()
if err != nil {
panic(err)
}

return filepath.Join(userConfigDir, "three-dots-labs")
}
98 changes: 98 additions & 0 deletions internal/update.go
@@ -0,0 +1,98 @@
package internal

import (
"context"
"encoding/json"
"fmt"
"github.com/fatih/color"
"net/http"
"os"
"path"
"time"
)

type releaseResponse struct {
TagName string `json:"tag_name"`
}

const repoURL = "https://github.com/ThreeDotsLabs/cli"
const releasesURL = "https://api.github.com/repos/ThreeDotsLabs/cli/releases/latest"

func CheckForUpdate(currentVersion string) {
if currentVersion == "" || currentVersion == "dev" {
return
}

lastUpdate, _ := LastUpdateCheckTime()

if time.Since(lastUpdate) < 24*time.Hour {
return
}

defer func() {
_ = StoreUpdateCheckTime(time.Now().UTC())
}()

ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, releasesURL, nil)
if err != nil {
return
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
return
}
defer func() {
_ = resp.Body.Close()
}()

var release releaseResponse
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
return
}

if release.TagName != currentVersion {
c := color.New(color.FgHiYellow)
_, _ = c.Printf("A new version is available: %s (current: %s)\n", release.TagName, currentVersion)
_, _ = c.Printf("Visit %v to update\n", repoURL)
fmt.Println()
}
}

func lastUpdateCheckPath() string {
return path.Join(GlobalConfigDir(), "last-update-check")
}

func LastUpdateCheckTime() (time.Time, error) {
if !fileExists(lastUpdateCheckPath()) {
return time.Time{}, nil
}

content, err := os.ReadFile(lastUpdateCheckPath())
if err != nil {
return time.Time{}, err
}

t, err := time.Parse(time.RFC3339, string(content))
if err != nil {
return time.Time{}, err
}

return t, nil
}

func StoreUpdateCheckTime(t time.Time) error {
return os.WriteFile(lastUpdateCheckPath(), []byte(t.Format(time.RFC3339)), 0644)
}

func fileExists(path string) bool {
_, err := os.Stat(path)
if err == nil {
return true
}

return false
}
13 changes: 12 additions & 1 deletion tdl/main.go
Expand Up @@ -50,7 +50,10 @@ var app = &cli.App{
return
}

fmt.Printf("%+v\n", err)
if err != nil {
fmt.Printf("%+v\n", err)
}

os.Exit(1)
},
Flags: []cli.Flag{
Expand All @@ -67,6 +70,9 @@ var app = &cli.App{
} else {
logrus.SetLevel(logrus.WarnLevel)
}

internal.CheckForUpdate(version)

return nil
},
Commands: []*cli.Command{
Expand All @@ -90,6 +96,10 @@ var app = &cli.App{
Usage: "do not verify certificate",
Hidden: true,
},
&cli.StringFlag{
Name: "region",
Usage: "the region to use (eu or us)",
},
&cli.BoolFlag{
Name: "override",
Usage: "if config already exists, it will be overridden",
Expand All @@ -106,6 +116,7 @@ var app = &cli.App{
c.Context,
token,
c.String("server"),
c.String("region"),
c.Bool("override"),
c.Bool("insecure"),
)
Expand Down
6 changes: 5 additions & 1 deletion trainings/api/protobuf/server.proto
Expand Up @@ -4,7 +4,7 @@ import "google/protobuf/empty.proto";
option go_package = "github.com/ThreeDotsLabs/cli/tdl-cli/trainings/genproto";

service Trainings {
rpc Init(InitRequest) returns (google.protobuf.Empty) {};
rpc Init(InitRequest) returns (InitResponse) {};

rpc GetTrainings(google.protobuf.Empty) returns (GetTrainingsResponse) {};
rpc StartTraining(StartTrainingRequest) returns (google.protobuf.Empty) {};
Expand All @@ -18,6 +18,10 @@ message InitRequest {
string token = 1;
}

message InitResponse {
string region = 1;
}

message Training {
string id = 1;
}
Expand Down
12 changes: 2 additions & 10 deletions trainings/config/global.go
Expand Up @@ -2,7 +2,6 @@ package config

import (
"fmt"
"os"
"path/filepath"
"strings"

Expand All @@ -16,19 +15,12 @@ import (
type GlobalConfig struct {
Token string `toml:"token"`
ServerAddr string `toml:"server_addr"`
Region string `toml:"region"`
Insecure bool `toml:"insecure"`
}

func globalConfigPath() string {
userConfigDir, err := os.UserConfigDir()
if err != nil {
panic(err)
}

configDir := filepath.Join(userConfigDir, "three-dots-labs")
configPath := filepath.Join(configDir, ".trainings-config")

return configPath
return filepath.Join(internal.GlobalConfigDir(), ".trainings-config")
}

func (c Config) ConfiguredGlobally() bool {
Expand Down
18 changes: 15 additions & 3 deletions trainings/configure.go
Expand Up @@ -8,23 +8,35 @@ import (
"github.com/ThreeDotsLabs/cli/trainings/genproto"
)

func (h *Handlers) ConfigureGlobally(ctx context.Context, token, serverAddr string, override, insecure bool) error {
func (h *Handlers) ConfigureGlobally(ctx context.Context, token, serverAddr, region string, override, insecure bool) error {
if !override && h.config.ConfiguredGlobally() {
return errors.New("trainings are already configured. Please pass --override flag to configure again")
}

if _, err := h.newGrpcClientWithAddr(ctx, serverAddr, insecure).Init(
if region != "" {
if region != "eu" && region != "us" {
return errors.New("region can be only eu or us")
}
}

resp, err := h.newGrpcClientWithAddr(ctx, serverAddr, region, insecure).Init(
ctxWithRequestHeader(ctx, h.cliMetadata),
&genproto.InitRequest{
Token: token,
},
); err != nil {
)
if err != nil {
return err
}

if region == "" {
region = resp.Region
}

return h.config.WriteGlobalConfig(config.GlobalConfig{
Token: token,
ServerAddr: serverAddr,
Region: region,
Insecure: insecure,
})
}

0 comments on commit e3d5bd8

Please sign in to comment.