Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit 01cd4c5

Browse files
author
Russtopia
committed
resync w/master
2 parents f64f649 + 045145b commit 01cd4c5

File tree

12 files changed

+147
-40
lines changed

12 files changed

+147
-40
lines changed

ci/build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ build(){
2727

2828
# Darwin builds do not work from Linux, so only try to build them from Darwin.
2929
# See: https://github.com/cdr/coder-cli/issues/20
30-
if [[ "$(uname)" -eq "Darwin" ]]; then
30+
if [[ "$(uname)" == "Darwin" ]]; then
3131
GOOS=linux build
3232
CGO_ENABLED=1 GOOS=darwin build
3333
exit 0

cmd/coder/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
)
1313

1414
var (
15-
version string
15+
version string = "No version built"
1616
)
1717

1818
type rootCmd struct{}

cmd/coder/shell.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@ import (
1212
"golang.org/x/sys/unix"
1313
"golang.org/x/time/rate"
1414
"golang.org/x/xerrors"
15+
"nhooyr.io/websocket"
1516

1617
"go.coder.com/cli"
1718
"go.coder.com/flog"
1819

20+
"cdr.dev/coder-cli/internal/activity"
1921
"cdr.dev/wsep"
2022
)
2123

22-
type shellCmd struct {
23-
}
24+
type shellCmd struct{}
2425

2526
func (cmd *shellCmd) Spec() cli.CommandSpec {
2627
return cli.CommandSpec{
@@ -126,6 +127,7 @@ func runCommand(ctx context.Context, envName string, command string, args []stri
126127
if err != nil {
127128
return err
128129
}
130+
go heatbeat(ctx, conn, 15*time.Second)
129131

130132
execer := wsep.RemoteExecer(conn)
131133
process, err := execer.Start(ctx, wsep.Command{
@@ -145,7 +147,10 @@ func runCommand(ctx context.Context, envName string, command string, args []stri
145147
go func() {
146148
stdin := process.Stdin()
147149
defer stdin.Close()
148-
_, err := io.Copy(stdin, os.Stdin)
150+
151+
ap := activity.NewPusher(entClient, env.ID, sshActivityName)
152+
wr := ap.Writer(stdin)
153+
_, err := io.Copy(wr, os.Stdin)
149154
if err != nil {
150155
cancel()
151156
}
@@ -168,3 +173,22 @@ func runCommand(ctx context.Context, envName string, command string, args []stri
168173
}
169174
return err
170175
}
176+
177+
func heatbeat(ctx context.Context, c *websocket.Conn, interval time.Duration) {
178+
ticker := time.NewTicker(interval)
179+
defer ticker.Stop()
180+
181+
for {
182+
select {
183+
case <-ctx.Done():
184+
return
185+
case <-ticker.C:
186+
err := c.Ping(ctx)
187+
if err != nil {
188+
flog.Error("failed to ping websocket: %v", err)
189+
}
190+
}
191+
}
192+
}
193+
194+
const sshActivityName = "ssh"

cmd/coder/sync.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ func (cmd *syncCmd) Run(fl *pflag.FlagSet) {
6969
}
7070

7171
s := sync.Sync{
72-
Init: cmd.init,
73-
Environment: env,
74-
RemoteDir: remoteDir,
75-
LocalDir: absLocal,
76-
Client: entClient,
72+
Init: cmd.init,
73+
Env: env,
74+
RemoteDir: remoteDir,
75+
LocalDir: absLocal,
76+
Client: entClient,
7777
}
7878
for err == nil || err == sync.ErrRestartSync {
7979
err = s.Run()

cmd/coder/url.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import (
1111
"go.coder.com/flog"
1212
)
1313

14-
type urlCmd struct {
15-
}
14+
type urlCmd struct{}
1615

1716
type DevURL struct {
1817
Url string `json:"url"`

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module cdr.dev/coder-cli
33
go 1.14
44

55
require (
6-
cdr.dev/wsep v0.0.0-20200615020153-e2b1c576fc40
6+
cdr.dev/wsep v0.0.0-20200616212001-0613cfe9a4ac
77
github.com/fatih/color v1.9.0 // indirect
88
github.com/gorilla/websocket v1.4.1
99
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f
@@ -16,7 +16,7 @@ require (
1616
go.coder.com/flog v0.0.0-20190906214207-47dd47ea0512
1717
golang.org/x/crypto v0.0.0-20200422194213-44a606286825
1818
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
19-
golang.org/x/sys v0.0.0-20200610111108-226ff32320da
19+
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1
2020
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
2121
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
2222
nhooyr.io/websocket v1.8.6

go.sum

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
11
cdr.dev/slog v1.3.0 h1:MYN1BChIaVEGxdS7I5cpdyMC0+WfJfK8BETAfzfLUGQ=
22
cdr.dev/slog v1.3.0/go.mod h1:C5OL99WyuOK8YHZdYY57dAPN1jK2WJlCdq2VP6xeQns=
3-
cdr.dev/wsep v0.0.0-20200602025116-5cbe721683df h1:9KgAywWKNQMYi3gvu4HyExiuXJhoNbnrPcb5RIzYSdQ=
4-
cdr.dev/wsep v0.0.0-20200602025116-5cbe721683df/go.mod h1:2VKClUml3gfmLez0gBxTJIjSKszpQotc2ZqPdApfK/Y=
5-
cdr.dev/wsep v0.0.0-20200612224539-e66f8bb64883 h1:nr/trZU6911y9PohrsVaujzJPrtN7bUSX7yfvenYbc0=
6-
cdr.dev/wsep v0.0.0-20200612224539-e66f8bb64883/go.mod h1:2VKClUml3gfmLez0gBxTJIjSKszpQotc2ZqPdApfK/Y=
7-
cdr.dev/wsep v0.0.0-20200613153816-ed81c4ad638b h1:cd2Fx+EBMWxWFMdODG/OWRhF9X8OWQ5DnsCEeCfd0Y4=
8-
cdr.dev/wsep v0.0.0-20200613153816-ed81c4ad638b/go.mod h1:2VKClUml3gfmLez0gBxTJIjSKszpQotc2ZqPdApfK/Y=
9-
cdr.dev/wsep v0.0.0-20200613225213-3384735ae5e5 h1:x6UJpHOO7mz//OrAdysmQIW+jdXAQ+n35eol5s+O6WU=
10-
cdr.dev/wsep v0.0.0-20200613225213-3384735ae5e5/go.mod h1:2VKClUml3gfmLez0gBxTJIjSKszpQotc2ZqPdApfK/Y=
11-
cdr.dev/wsep v0.0.0-20200613231142-71da214c188e h1:ZOQoyb0N07vc9MMet/IQFCpKSObcZZt9o+nPFz7/zNM=
12-
cdr.dev/wsep v0.0.0-20200613231142-71da214c188e/go.mod h1:2VKClUml3gfmLez0gBxTJIjSKszpQotc2ZqPdApfK/Y=
133
cdr.dev/wsep v0.0.0-20200615020153-e2b1c576fc40 h1:f369880iSAZ3cXwvbdc9WIyy3FZ4yanusYZjaVHeis4=
144
cdr.dev/wsep v0.0.0-20200615020153-e2b1c576fc40/go.mod h1:2VKClUml3gfmLez0gBxTJIjSKszpQotc2ZqPdApfK/Y=
5+
cdr.dev/wsep v0.0.0-20200616212001-0613cfe9a4ac h1:rl4O0qfxgNRWBUe5gQu4of2cdsclcpjGYmLQhSCHX7c=
6+
cdr.dev/wsep v0.0.0-20200616212001-0613cfe9a4ac/go.mod h1:2VKClUml3gfmLez0gBxTJIjSKszpQotc2ZqPdApfK/Y=
157
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
168
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
179
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -126,8 +118,6 @@ github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDS
126118
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
127119
github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8=
128120
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
129-
github.com/klauspost/compress v1.10.7 h1:7rix8v8GpI3ZBb0nSozFRgbtXKv+hOe+qfEpZqybrAg=
130-
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
131121
github.com/klauspost/compress v1.10.8 h1:eLeJ3dr/Y9+XRfJT4l+8ZjmtB5RPJhucH2HeCV5+IZY=
132122
github.com/klauspost/compress v1.10.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
133123
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@@ -250,10 +240,10 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
250240
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
251241
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
252242
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
253-
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
254-
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
255243
golang.org/x/sys v0.0.0-20200610111108-226ff32320da h1:bGb80FudwxpeucJUjPYJXuJ8Hk91vNtfvrymzwiei38=
256244
golang.org/x/sys v0.0.0-20200610111108-226ff32320da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
245+
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
246+
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
257247
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
258248
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
259249
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=

internal/activity/pusher.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package activity
2+
3+
import (
4+
"time"
5+
6+
"cdr.dev/coder-cli/internal/entclient"
7+
"go.coder.com/flog"
8+
"golang.org/x/time/rate"
9+
)
10+
11+
const pushInterval = time.Minute
12+
13+
// Pusher pushes activity metrics no more than once per pushInterval. Pushes
14+
// within the same interval are a no-op.
15+
type Pusher struct {
16+
envID string
17+
source string
18+
19+
client *entclient.Client
20+
rate *rate.Limiter
21+
}
22+
23+
func NewPusher(c *entclient.Client, envID, source string) *Pusher {
24+
return &Pusher{
25+
envID: envID,
26+
source: source,
27+
client: c,
28+
rate: rate.NewLimiter(rate.Every(pushInterval), 1),
29+
}
30+
}
31+
32+
func (p *Pusher) Push() {
33+
if !p.rate.Allow() {
34+
return
35+
}
36+
37+
err := p.client.PushActivity(p.source, p.envID)
38+
if err != nil {
39+
flog.Error("push activity: %s", err.Error())
40+
}
41+
}

internal/activity/writer.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package activity
2+
3+
import "io"
4+
5+
type activityWriter struct {
6+
p *Pusher
7+
wr io.Writer
8+
}
9+
10+
func (w *activityWriter) Write(p []byte) (n int, err error) {
11+
w.p.Push()
12+
return w.wr.Write(p)
13+
}
14+
15+
func (p *Pusher) Writer(wr io.Writer) io.Writer {
16+
return &activityWriter{p: p, wr: wr}
17+
}

internal/entclient/activity.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package entclient
2+
3+
import "net/http"
4+
5+
func (c Client) PushActivity(source string, envID string) error {
6+
res, err := c.request("POST", "/api/metrics/usage/push", map[string]string{
7+
"source": source,
8+
"environment_id": envID,
9+
})
10+
if err != nil {
11+
return err
12+
}
13+
14+
if res.StatusCode != http.StatusOK {
15+
return bodyError(res)
16+
}
17+
18+
return nil
19+
}

internal/entclient/client.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ type Client struct {
1212
}
1313

1414
func (c Client) copyURL() *url.URL {
15-
return &(*c.BaseURL)
15+
swp := *c.BaseURL
16+
return &swp
1617
}
1718

1819
func (c *Client) http() (*http.Client, error) {

internal/sync/sync.go

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"go.coder.com/flog"
2323

24+
"cdr.dev/coder-cli/internal/activity"
2425
"cdr.dev/coder-cli/internal/entclient"
2526
"cdr.dev/wsep"
2627
)
@@ -33,8 +34,11 @@ type Sync struct {
3334
LocalDir string
3435
// RemoteDir is an absolute path.
3536
RemoteDir string
36-
entclient.Environment
37-
*entclient.Client
37+
// DisableMetrics disables activity metric pushing.
38+
DisableMetrics bool
39+
40+
Env entclient.Environment
41+
Client *entclient.Client
3842
}
3943

4044
func (s Sync) syncPaths(delete bool, local, remote string) error {
@@ -43,7 +47,7 @@ func (s Sync) syncPaths(delete bool, local, remote string) error {
4347
args := []string{"-zz",
4448
"-a",
4549
"--delete",
46-
"-e", self + " sh", local, s.Environment.Name + ":" + remote,
50+
"-e", self + " sh", local, s.Env.Name + ":" + remote,
4751
}
4852
if delete {
4953
args = append([]string{"--delete"}, args...)
@@ -99,7 +103,7 @@ func (s Sync) remoteMkDir() error {
99103
}
100104

101105
func (s Sync) remoteRm(ctx context.Context, remote string) error {
102-
conn, err := s.Client.DialWsep(ctx, s.Environment)
106+
conn, err := s.Client.DialWsep(ctx, s.Env)
103107
if err != nil {
104108
return err
105109
}
@@ -260,13 +264,16 @@ func (s Sync) workEventGroup(evs []timedEvent) {
260264
}
261265

262266
const (
263-
// maxinflightInotify sets the maximum number of inotifies before the sync just restarts.
264-
// Syncing a large amount of small files (e.g .git or node_modules) is impossible to do performantly
265-
// with individual rsyncs.
267+
// maxinflightInotify sets the maximum number of inotifies before the
268+
// sync just restarts. Syncing a large amount of small files (e.g .git
269+
// or node_modules) is impossible to do performantly with individual
270+
// rsyncs.
266271
maxInflightInotify = 8
267272
maxEventDelay = time.Second * 7
268-
// maxAcceptableDispatch is the maximum amount of time before an event should begin its journey to the server.
269-
// This sets a lower bound for perceivable latency, but the higher it is, the better the optimization.
273+
// maxAcceptableDispatch is the maximum amount of time before an event
274+
// should begin its journey to the server. This sets a lower bound for
275+
// perceivable latency, but the higher it is, the better the
276+
// optimization.
270277
maxAcceptableDispatch = time.Millisecond * 50
271278
)
272279

@@ -276,14 +283,19 @@ const (
276283
func (s Sync) Run() error {
277284
events := make(chan notify.EventInfo, maxInflightInotify)
278285
// Set up a recursive watch.
279-
// We do this before the initial sync so we can capture any changes that may have happened during sync.
286+
// We do this before the initial sync so we can capture any changes
287+
// that may have happened during sync.
280288
err := notify.Watch(path.Join(s.LocalDir, "..."), events, notify.All)
281289
if err != nil {
282290
return xerrors.Errorf("create watch: %w", err)
283291
}
284292
defer notify.Stop(events)
285293

286294
s.remoteMkDir()
295+
296+
ap := activity.NewPusher(s.Client, s.Env.ID, activityName)
297+
ap.Push()
298+
287299
setConsoleTitle("⏳ syncing project")
288300
err = s.initSync()
289301
if err != nil {
@@ -297,7 +309,8 @@ func (s Sync) Run() error {
297309
flog.Info("watching %s for changes", s.LocalDir)
298310

299311
var droppedEvents uint64
300-
// Timed events lets us track how long each individual file takes to update.
312+
// Timed events lets us track how long each individual file takes to
313+
// update.
301314
timedEvents := make(chan timedEvent, cap(events))
302315
go func() {
303316
defer close(timedEvents)
@@ -341,6 +354,9 @@ func (s Sync) Run() error {
341354
}
342355
s.workEventGroup(eventGroup)
343356
eventGroup = eventGroup[:0]
357+
ap.Push()
344358
}
345359
}
346360
}
361+
362+
const activityName = "sync"

0 commit comments

Comments
 (0)