Skip to content

Commit e0d4869

Browse files
committed
feat(controller-sdk-go): change log api to websocket
1 parent 801edf7 commit e0d4869

2 files changed

Lines changed: 63 additions & 55 deletions

File tree

apps/apps.go

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import (
55
"encoding/json"
66
"errors"
77
"fmt"
8-
"io/ioutil"
9-
"strconv"
8+
"net/http"
9+
"net/url"
1010

1111
drycc "github.com/drycc/controller-sdk-go"
1212
"github.com/drycc/controller-sdk-go/api"
13+
"github.com/gorilla/websocket"
1314
)
1415

1516
// ErrNoLogs is returned when logs are missing from an app.
@@ -88,26 +89,30 @@ func Get(c *drycc.Client, appID string) (api.App, error) {
8889

8990
// Logs retrieves logs from an app. The number of log lines fetched can be set by the lines
9091
// argument. Setting lines = -1 will retrieve all app logs.
91-
func Logs(c *drycc.Client, appID string, lines int) (string, error) {
92-
u := fmt.Sprintf("/v2/apps/%s/logs", appID)
93-
94-
if lines > 0 {
95-
u += "?log_lines=" + strconv.Itoa(lines)
96-
}
97-
98-
res, reqErr := c.Request("GET", u, nil)
99-
if reqErr != nil && !drycc.IsErrAPIMismatch(reqErr) {
100-
return "", ErrNoLogs
101-
}
102-
defer res.Body.Close()
103-
104-
body, err := ioutil.ReadAll(res.Body)
105-
if err != nil || len(body) < 3 {
106-
return "", ErrNoLogs
92+
func Logs(c *drycc.Client, appID string, lines int, follow bool, timeout int) (*websocket.Conn, error) {
93+
scheme := "ws"
94+
if c.ControllerURL.Scheme == "https" {
95+
scheme = "wss"
96+
}
97+
path := fmt.Sprintf("v2/apps/%s/logs", appID)
98+
endpoint := url.URL{Scheme: scheme, Host: c.ControllerURL.Host, Path: path}
99+
conn, _, err := websocket.DefaultDialer.Dial(
100+
endpoint.String(),
101+
http.Header{
102+
"User-Agent": {c.UserAgent},
103+
"Authorization": {"token " + c.Token},
104+
"X-Drycc-Builder-Auth": {c.HooksToken},
105+
},
106+
)
107+
if err != nil {
108+
return nil, err
107109
}
108110

109-
// We need to trim a few characters off the front and end of the string
110-
return string(body), reqErr
111+
conn.WriteMessage(
112+
websocket.TextMessage,
113+
[]byte(fmt.Sprintf(`{"lines": %d, "timeout": %d, "follow": %v}`, lines, timeout, follow)),
114+
)
115+
return conn, nil
111116
}
112117

113118
// Run a one-time command in your app. This will start a kubernetes job with the

apps/apps_test.go

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package apps
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"io/ioutil"
7+
"log"
68
"net/http"
79
"net/http/httptest"
810
"reflect"
911
"testing"
1012

1113
drycc "github.com/drycc/controller-sdk-go"
1214
"github.com/drycc/controller-sdk-go/api"
15+
"github.com/gorilla/websocket"
1316
)
1417

1518
const appFixture string = `
@@ -43,11 +46,19 @@ const appCreateExpected string = `{"id":"example-go"}`
4346
const appRunExpected string = `{"command":"echo hi"}`
4447
const appTransferExpected string = `{"owner":"test"}`
4548

49+
var upgrader = websocket.Upgrader{} // use default options
50+
4651
type fakeHTTPServer struct {
4752
createID bool
4853
createWithoutID bool
4954
}
5055

56+
type fakeLogReqMessage struct {
57+
Lines int `json:"lines"`
58+
Timeout int `json:"timeout"`
59+
Follow bool `json:"follow"`
60+
}
61+
5162
func (f *fakeHTTPServer) ServeHTTP(res http.ResponseWriter, req *http.Request) {
5263
res.Header().Add("DRYCC_API_VERSION", drycc.APIVersion)
5364

@@ -96,15 +107,23 @@ func (f *fakeHTTPServer) ServeHTTP(res http.ResponseWriter, req *http.Request) {
96107

97108
// The entire log message is prefixed and suffixed with a few characters (not entirely sure why)
98109
// We mimic those here
99-
if req.URL.Path == "/v2/apps/example-go/logs" && req.URL.RawQuery == "" && req.Method == "GET" {
100-
res.Write([]byte(`test\nfoo\nbar`))
101-
return
102-
}
103-
104-
// The entire log message is prefixed and suffixed with a few characters (not entirely sure why)
105-
// We mimic those here
106-
if req.URL.Path == "/v2/apps/example-go/logs" && req.URL.RawQuery == "log_lines=1" && req.Method == "GET" {
107-
res.Write([]byte("test"))
110+
if req.URL.Path == "/v2/apps/example-go/logs" {
111+
c, err := upgrader.Upgrade(res, req, nil)
112+
if err != nil {
113+
log.Print("upgrade:", err)
114+
return
115+
}
116+
defer c.Close()
117+
_, message, err := c.ReadMessage()
118+
if err != nil {
119+
log.Print("upgrade:", err)
120+
return
121+
}
122+
reqJSON := fakeLogReqMessage{}
123+
json.Unmarshal([]byte(message), &reqJSON)
124+
for i := 0; i < reqJSON.Lines; i++ {
125+
c.WriteMessage(websocket.TextMessage, []byte(fmt.Sprintf("test %d", i)))
126+
}
108127
return
109128
}
110129

@@ -296,25 +315,9 @@ func TestAppsList(t *testing.T) {
296315
}
297316
}
298317

299-
type testExpected struct {
300-
Input int
301-
Expected string
302-
}
303-
304318
func TestAppsLogs(t *testing.T) {
305319
t.Parallel()
306320

307-
tests := []testExpected{
308-
{
309-
Input: -1,
310-
Expected: `test\nfoo\nbar`,
311-
},
312-
{
313-
Input: 1,
314-
Expected: "test",
315-
},
316-
}
317-
318321
handler := fakeHTTPServer{}
319322
server := httptest.NewServer(&handler)
320323
defer server.Close()
@@ -324,16 +327,16 @@ func TestAppsLogs(t *testing.T) {
324327
t.Fatal(err)
325328
}
326329

327-
for _, test := range tests {
328-
actual, err := Logs(drycc, "example-go", test.Input)
329-
330-
if err != nil {
331-
t.Error(err)
332-
}
333-
334-
if actual != test.Expected {
335-
t.Errorf("Expected %s, Got %s", test.Expected, actual)
336-
}
330+
conn, err := Logs(drycc, "example-go", 1, false, 300)
331+
if err != nil {
332+
t.Fatal(err)
333+
}
334+
_, message, err := conn.ReadMessage()
335+
if err != nil {
336+
t.Fatal(err)
337+
}
338+
if string(message) != "test 0" {
339+
t.Errorf("Expected %s, Got %s", "test 0", message)
337340
}
338341
}
339342

0 commit comments

Comments
 (0)