GoLang
Simple Go script to upload a capture zip file.
It retrieves an authentication token using the client_id
and client_secret
found in your Developer Dashboard.
Read the Quick Start Guide and the Upload Captures pages to learn more.
⚠️ To run this you need Go 1.19+.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
)
const (
ClientID = "insert-it-here"
ClientSecret = "insert-it-here"
AuthEndpoint = "https://signin.teleport.varjo.com/oauth2/token"
ApiBase = "https://teleport.varjo.com"
)
type AuthResponse struct {
AccessToken string `json:"access_token"`
}
type CreateCaptureResponse struct {
Eid string `json:"eid"`
NumParts int `json:"num_parts"`
ChunkSize int64 `json:"chunk_size"`
}
type UploadURLResponse struct {
UploadURL string `json:"upload_url"`
}
type UploadedPart struct {
Number int `json:"number"`
ETag string `json:"etag"`
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Usage: go run upload_capture.go <file>")
os.Exit(1)
}
filename := os.Args[1]
file, err := os.Open(filename)
if err != nil {
fmt.Println("Error opening file:", err)
os.Exit(1)
}
defer file.Close()
fileInfo, _ := file.Stat()
bytesize := fileInfo.Size()
fmt.Printf("Uploading capture of %d bytes...\n", bytesize)
// Step 1: Authenticate
token, err := getAuthToken()
if err != nil {
fmt.Println("Authentication failed:", err)
os.Exit(1)
}
// Step 2: Create capture
eid, numParts, chunkSize, err := createCapture(token, filename, bytesize)
if err != nil {
fmt.Println("Failed to create capture:", err)
os.Exit(1)
}
fmt.Printf("Uploading %d parts...\n", numParts)
parts := make([]UploadedPart, 0, numParts)
for partNo := 1; partNo <= numParts; partNo++ {
uploadURL, err := getUploadURL(token, eid, bytesize, partNo)
if err != nil {
fmt.Printf("Failed to get upload URL for part %d: %v\n", partNo, err)
os.Exit(1)
}
part := make([]byte, chunkSize)
n, err := file.Read(part)
if err != nil && err != io.EOF {
fmt.Println("Error reading file:", err)
os.Exit(1)
}
fmt.Printf("Uploading part %d...\n", partNo)
etag, err := uploadPart(uploadURL, part[:n])
if err != nil {
fmt.Printf("Failed to upload part %d: %v\n", partNo, err)
os.Exit(1)
}
parts = append(parts, UploadedPart{Number: partNo, ETag: etag})
}
// Step 3: Notify completion
state, err := finalizeUpload(token, eid, parts)
if err != nil {
fmt.Println("Failed to finalize upload:", err)
os.Exit(1)
}
fmt.Println("Upload done!")
fmt.Println("Capture state:", state)
}
func getAuthToken() (string, error) {
data := url.Values{}
data.Set("grant_type", "client_credentials")
data.Set("client_id", ClientID)
data.Set("client_secret", ClientSecret)
data.Set("scope", "openid profile email")
resp, err := http.PostForm(AuthEndpoint, data)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("status %d", resp.StatusCode)
}
var result AuthResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", err
}
return result.AccessToken, nil
}
func createCapture(token, filename string, bytesize int64) (string, int, int64, error) {
payload := map[string]interface{}{
"name": filepath.Base(filename),
"bytesize": bytesize,
"input_data_format": "bulk-images",
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", ApiBase+"/api/v1/captures", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", 0, 0, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", 0, 0, fmt.Errorf("status %d", resp.StatusCode)
}
var data CreateCaptureResponse
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return "", 0, 0, err
}
return data.Eid, data.NumParts, data.ChunkSize, nil
}
func getUploadURL(token, eid string, bytesize int64, partNo int) (string, error) {
payload := map[string]interface{}{
"eid": eid,
"bytesize": bytesize,
}
body, _ := json.Marshal(payload)
url := fmt.Sprintf("%s/api/v1/captures/%s/create-upload-url/%d", ApiBase, eid, partNo)
req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("status %d", resp.StatusCode)
}
var data UploadURLResponse
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return "", err
}
return data.UploadURL, nil
}
func uploadPart(uploadURL string, data []byte) (string, error) {
req, _ := http.NewRequest("PUT", uploadURL, bytes.NewReader(data))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("status %d", resp.StatusCode)
}
etag := resp.Header.Get("ETag")
if len(etag) > 0 {
etag = etag[1 : len(etag)-1] // remove quotes
}
return etag, nil
}
func finalizeUpload(token, eid string, parts []UploadedPart) (string, error) {
payload := map[string]interface{}{
"eid": eid,
"parts": parts,
}
body, _ := json.Marshal(payload)
url := fmt.Sprintf("%s/api/v1/captures/%s/uploaded", ApiBase, eid)
req, _ := http.NewRequest("POST", url, bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("status %d", resp.StatusCode)
}
var data map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return "", err
}
state, _ := data["state"].(string)
return state, nil
}