Skip to content

Commit 2d11bca

Browse files
committed
Merge branch 'main' into dan/agents-regional-logs
2 parents 3ddd302 + 03d2fcf commit 2d11bca

File tree

11 files changed

+171
-28
lines changed

11 files changed

+171
-28
lines changed

.github/workflows/build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
key: livekit-cli
3535

3636
- name: Set up Go
37-
uses: actions/setup-go@v5
37+
uses: actions/setup-go@v6
3838
with:
3939
go-version: "1.25"
4040

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
key: livekit-cli
4949

5050
- name: Set up Go
51-
uses: actions/setup-go@v5
51+
uses: actions/setup-go@v6
5252
with:
5353
go-version: "1.25"
5454

.github/workflows/test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ jobs:
1919
packages: read
2020

2121
steps:
22-
- uses: actions/checkout@v4
22+
- uses: actions/checkout@v5
2323

2424
- name: Set up Go
25-
uses: actions/setup-go@v4
25+
uses: actions/setup-go@v6
2626
with:
2727
go-version: "1.25"
2828
cache: true

cmd/lk/agent.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,6 @@ func initAgent(ctx context.Context, cmd *cli.Command) error {
402402
if appName == "" {
403403
appName = project.Name
404404
}
405-
// We set agent name in env for use in template tasks
406-
os.Setenv("LIVEKIT_AGENT_NAME", appName)
407405

408406
// TODO: (@rektdeckard) figure out why AccessKeyProvider does not immediately
409407
// have access to newly-created API keys, then remove this sleep
@@ -416,6 +414,11 @@ func initAgent(ctx context.Context, cmd *cli.Command) error {
416414
token,
417415
serverURL,
418416
)
417+
418+
// We set agent name and sandbox ID in env for use in template tasks
419+
os.Setenv("LIVEKIT_AGENT_NAME", appName)
420+
os.Setenv("LIVEKIT_SANDBOX_ID", sandboxID)
421+
419422
return err
420423
}); err != nil {
421424
return fmt.Errorf("failed to create sandbox: %w", err)

cmd/lk/sip.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,10 @@ var (
369369
Usage: "timeout for the call to dial",
370370
Value: 80 * time.Second,
371371
},
372+
&cli.StringSliceFlag{
373+
Name: "header",
374+
Usage: "Custom SIP header in format 'Key:Value' (can be specified multiple times)",
375+
},
372376
},
373377
},
374378
{
@@ -1154,6 +1158,26 @@ func createSIPParticipant(ctx context.Context, cmd *cli.Command) error {
11541158
if cmd.Bool("wait") {
11551159
req.WaitUntilAnswered = true
11561160
}
1161+
1162+
// Parse headers from repeatable "header" flag
1163+
if headers := cmd.StringSlice("header"); len(headers) > 0 {
1164+
if req.Headers == nil {
1165+
req.Headers = make(map[string]string)
1166+
}
1167+
for _, header := range headers {
1168+
parts := strings.SplitN(header, ":", 2)
1169+
if len(parts) != 2 {
1170+
return fmt.Errorf("invalid header format '%s', expected 'Key:Value'", header)
1171+
}
1172+
key := strings.TrimSpace(parts[0])
1173+
value := strings.TrimSpace(parts[1])
1174+
if key == "" {
1175+
return fmt.Errorf("header key cannot be empty in '%s'", header)
1176+
}
1177+
req.Headers[key] = value
1178+
}
1179+
}
1180+
11571181
return req.Validate()
11581182
}, func(ctx context.Context, req *livekit.CreateSIPParticipantRequest) (*livekit.SIPParticipantInfo, error) {
11591183
// CreateSIPParticipant will wait for LiveKit Participant to be created and that can take some time.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ require (
1414
github.com/go-logr/logr v1.4.3
1515
github.com/go-task/task/v3 v3.44.1
1616
github.com/joho/godotenv v1.5.1
17-
github.com/livekit/protocol v1.42.1-0.20251001181643-1c8cbd7cbbb5
17+
github.com/livekit/protocol v1.42.1-0.20251008181454-49a136864c2d
1818
github.com/livekit/server-sdk-go/v2 v2.11.3
1919
github.com/moby/buildkit v0.23.2
2020
github.com/moby/patternmatcher v0.6.0

go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,10 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT
274274
github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ=
275275
github.com/livekit/mediatransportutil v0.0.0-20250825135402-7bc31f107ade h1:lpxPcglwzUWNB4J0S2qZuyMehzmR7vW9whzSwV4IGoI=
276276
github.com/livekit/mediatransportutil v0.0.0-20250825135402-7bc31f107ade/go.mod h1:mSNtYzSf6iY9xM3UX42VEI+STHvMgHmrYzEHPcdhB8A=
277-
github.com/livekit/protocol v1.42.1-0.20251001181643-1c8cbd7cbbb5 h1:TAvDDQDVO0t63gv3d6xGntWRflVJLRdqPTMgMi8hzdY=
278-
github.com/livekit/protocol v1.42.1-0.20251001181643-1c8cbd7cbbb5/go.mod h1:vhMS30QoEyH2p34vi6X1eWkC4EMV72ZGZwQb74ajY7A=
277+
github.com/livekit/protocol v1.42.1-0.20250929175250-2ddfb3ee7f7e h1:yytr+uwFXtJ8UxBV2q3j55jVKg7zslECuGeE4F56NoU=
278+
github.com/livekit/protocol v1.42.1-0.20250929175250-2ddfb3ee7f7e/go.mod h1:vhMS30QoEyH2p34vi6X1eWkC4EMV72ZGZwQb74ajY7A=
279+
github.com/livekit/protocol v1.42.1-0.20251008181454-49a136864c2d h1:ofC+CPiYDZ4LD+RgIJg4rUFLvKnWJqg66bn00FALKLI=
280+
github.com/livekit/protocol v1.42.1-0.20251008181454-49a136864c2d/go.mod h1:vhMS30QoEyH2p34vi6X1eWkC4EMV72ZGZwQb74ajY7A=
279281
github.com/livekit/psrpc v0.7.0 h1:rtfqfjYN06WJYloE/S0nmkJ/Y04x4pxLQLe8kQ4FVHU=
280282
github.com/livekit/psrpc v0.7.0/go.mod h1:AuDC5uOoEjQJEc69v4Li3t77Ocz0e0NdjQEuFfO+vfk=
281283
github.com/livekit/server-sdk-go/v2 v2.11.3 h1:k+YDxo8wPCixRrS9fJHcbtlurlXhVLfyPva5Ne4tVH0=

pkg/agentfs/client.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,13 @@ func (c *Client) CreateAgent(
112112
if err != nil {
113113
return nil, err
114114
}
115-
if err := c.uploadAndBuild(ctx, resp.AgentId, resp.PresignedUrl, workingDir, excludeFiles); err != nil {
115+
if err := c.uploadAndBuild(ctx,
116+
resp.AgentId,
117+
resp.PresignedUrl,
118+
resp.PresignedPostRequest,
119+
workingDir,
120+
excludeFiles,
121+
); err != nil {
116122
return nil, err
117123
}
118124
return resp, nil
@@ -136,14 +142,15 @@ func (c *Client) DeployAgent(
136142
if !resp.Success {
137143
return fmt.Errorf("failed to deploy agent: %s", resp.Message)
138144
}
139-
return c.uploadAndBuild(ctx, agentID, resp.PresignedUrl, workingDir, excludeFiles)
145+
return c.uploadAndBuild(ctx, agentID, resp.PresignedUrl, resp.PresignedPostRequest, workingDir, excludeFiles)
140146
}
141147

142148
// uploadAndBuild uploads the source and triggers remote build
143149
func (c *Client) uploadAndBuild(
144150
ctx context.Context,
145151
agentID string,
146152
presignedUrl string,
153+
presignedPostRequest *lkproto.PresignedPostRequest,
147154
workingDir string,
148155
excludeFiles []string,
149156
) error {
@@ -154,6 +161,7 @@ func (c *Client) uploadAndBuild(
154161
if err := UploadTarball(
155162
workingDir,
156163
presignedUrl,
164+
presignedPostRequest,
157165
excludeFiles,
158166
projectType,
159167
); err != nil {

pkg/agentfs/tar.go

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"compress/gzip"
2121
"fmt"
2222
"io"
23+
"mime/multipart"
2324
"net/http"
2425
"os"
2526
"path"
@@ -29,6 +30,7 @@ import (
2930
"github.com/schollz/progressbar/v3"
3031

3132
"github.com/livekit/livekit-cli/v2/pkg/util"
33+
"github.com/livekit/protocol/livekit"
3234
"github.com/livekit/protocol/logger"
3335

3436
"github.com/moby/patternmatcher"
@@ -51,7 +53,13 @@ var (
5153
}
5254
)
5355

54-
func UploadTarball(directory string, presignedUrl string, excludeFiles []string, projectType ProjectType) error {
56+
func UploadTarball(
57+
directory string,
58+
presignedUrl string,
59+
presignedPostRequest *livekit.PresignedPostRequest,
60+
excludeFiles []string,
61+
projectType ProjectType,
62+
) error {
5563
excludeFiles = append(excludeFiles, defaultExcludePatterns...)
5664

5765
loadExcludeFiles := func(filename string) (bool, string, error) {
@@ -274,25 +282,73 @@ func UploadTarball(directory string, presignedUrl string, excludeFiles []string,
274282
}),
275283
)
276284

277-
req, err := http.NewRequest("PUT", presignedUrl, io.TeeReader(&buffer, uploadProgress))
285+
if presignedPostRequest != nil {
286+
if err := multipartUpload(presignedPostRequest.Url, presignedPostRequest.Values, &buffer); err != nil {
287+
return fmt.Errorf("multipart upload failed: %w", err)
288+
}
289+
} else {
290+
if err := upload(presignedUrl, &buffer, uploadProgress); err != nil {
291+
return fmt.Errorf("upload failed: %w", err)
292+
}
293+
}
294+
295+
return nil
296+
}
297+
298+
func upload(presignedUrl string, buffer *bytes.Buffer, uploadProgress *progressbar.ProgressBar) error {
299+
req, err := http.NewRequest("PUT", presignedUrl, io.TeeReader(buffer, uploadProgress))
278300
if err != nil {
279301
return fmt.Errorf("failed to create request: %w", err)
280302
}
281303
req.Header.Set("Content-Type", "application/gzip")
282304
req.ContentLength = int64(buffer.Len())
283-
284-
client := &http.Client{}
285-
resp, err := client.Do(req)
305+
resp, err := http.DefaultClient.Do(req)
286306
if err != nil {
287307
return fmt.Errorf("failed to upload tarball: %w", err)
288308
}
289309
defer resp.Body.Close()
290-
291310
if resp.StatusCode != http.StatusOK {
292311
body, _ := io.ReadAll(resp.Body)
293312
return fmt.Errorf("failed to upload tarball: %d: %s", resp.StatusCode, body)
294313
}
314+
return nil
315+
}
295316

296-
fmt.Println()
317+
func multipartUpload(presignedURL string, fields map[string]string, buf *bytes.Buffer) error {
318+
var b bytes.Buffer
319+
w := multipart.NewWriter(&b)
320+
fileName, ok := fields["key"]
321+
if !ok {
322+
fileName = "upload.tar.gz"
323+
}
324+
for k, v := range fields {
325+
if err := w.WriteField(k, v); err != nil {
326+
return err
327+
}
328+
}
329+
part, err := w.CreateFormFile("file", fileName)
330+
if err != nil {
331+
return err
332+
}
333+
if _, err := io.Copy(part, buf); err != nil {
334+
return err
335+
}
336+
if err := w.Close(); err != nil {
337+
return err
338+
}
339+
req, err := http.NewRequest("POST", presignedURL, &b)
340+
if err != nil {
341+
return err
342+
}
343+
req.Header.Set("Content-Type", w.FormDataContentType())
344+
resp, err := http.DefaultClient.Do(req)
345+
if err != nil {
346+
return err
347+
}
348+
defer resp.Body.Close()
349+
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusNoContent {
350+
respBody, _ := io.ReadAll(resp.Body)
351+
return fmt.Errorf("failed to upload tarball: %d: %s", resp.StatusCode, respBody)
352+
}
297353
return nil
298354
}

0 commit comments

Comments
 (0)