Skip to content

Commit

Permalink
Add formating
Browse files Browse the repository at this point in the history
  • Loading branch information
lloesche committed Mar 20, 2024
1 parent bfc5cea commit 465319a
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 53 deletions.
24 changes: 24 additions & 0 deletions format/format.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package format

import (
"encoding/json"

"gopkg.in/yaml.v2"
)

func ToJSON(data interface{}) (string, error) {
bytes, err := json.Marshal(data)
if err != nil {
return "", err
}
bytes = append(bytes, '\n')
return string(bytes), nil
}

func ToYAML(data interface{}) (string, error) {
bytes, err := yaml.Marshal(data)
if err != nil {
return "", err
}
return string(bytes), nil
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/someengineering/fixctl

go 1.22.1

require gopkg.in/yaml.v2 v2.4.0
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
42 changes: 37 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"

"github.com/someengineering/fixctl/auth"
"github.com/someengineering/fixctl/format"
"github.com/someengineering/fixctl/search"
"github.com/someengineering/fixctl/utils"
)
Expand All @@ -17,6 +18,8 @@ func main() {
searchStrPtr := flag.String("search", "", "Search string")
usernamePtr := flag.String("username", "", "Username")
passwordPtr := flag.String("password", "", "Password")
formatPtr := flag.String("format", "json", "Output format: json or yaml")
withEdgesPtr := flag.Bool("with-edges", false, "Include edges in search results")
flag.Parse()

apiEndpoint := utils.GetEnvOrDefault("FIX_API_ENDPOINT", *apiEndpointPtr)
Expand All @@ -25,6 +28,8 @@ func main() {
fixToken := utils.GetEnvOrDefault("FIX_TOKEN", *fixTokenPtr)
workspaceID := utils.GetEnvOrDefault("FIX_WORKSPACE", *workspacePtr)
searchStr := *searchStrPtr
withEdges := *withEdgesPtr
outputFormat := *formatPtr

if apiEndpoint == "" {
apiEndpoint = "https://app.fix.security"
Expand All @@ -33,6 +38,10 @@ func main() {
fmt.Println("Workspace ID is required")
os.Exit(1)
}
if outputFormat != "json" && outputFormat != "yaml" {
fmt.Println("Invalid output format")
os.Exit(1)
}

if fixToken == "" && username != "" && password != "" {
var err error
Expand All @@ -42,12 +51,35 @@ func main() {
return
}
}
if fixToken == "" {
fmt.Println("Either token or username and password are required")
os.Exit(1)
}

response, err := search.SearchTable(apiEndpoint, fixToken, workspaceID, searchStr)
if err != nil {
fmt.Println("Search error:", err)
return
results, errs := search.SearchTable(apiEndpoint, fixToken, workspaceID, searchStr, withEdges)
firstResult := true
for result := range results {
var output string
var err error
switch outputFormat {
case "yaml":
if !firstResult {
fmt.Println("---")
} else {
firstResult = false
}
output, err = format.ToYAML(result)
default:
output, err = format.ToJSON(result)
}
if err != nil {
fmt.Printf("Error formatting output: %v\n", err)
os.Exit(2)
}
fmt.Print(output)
}

fmt.Println(response)
if err, ok := <-errs; ok {
fmt.Println("Search error:", err)
}
}
103 changes: 55 additions & 48 deletions search/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,66 +2,73 @@
package search

import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)

// SearchRequest defines the structure of the search request body
type SearchRequest struct {
Query string `json:"query"`
Skip int `json:"skip"`
Limit int `json:"limit"`
Count bool `json:"count"`
Sort []SortField `json:"sort"`
Query string `json:"query"`
WithEdges bool `json:"with_edges"`
}

// SortField defines the structure of the sort field in the search request
type SortField struct {
Path string `json:"path"`
Direction string `json:"direction"`
}
func SearchTable(apiEndpoint, fixToken, workspaceID, searchStr string, withEdges bool) (<-chan interface{}, <-chan error) {
results := make(chan interface{})
errs := make(chan error, 1)

go func() {
defer close(results)
defer close(errs)
requestBody, err := json.Marshal(SearchRequest{
Query: searchStr,
WithEdges: withEdges,
})
if err != nil {
errs <- fmt.Errorf("error marshaling JSON: %w", err)
return
}

url := fmt.Sprintf("%s/api/workspaces/%s/inventory/search", apiEndpoint, workspaceID)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
errs <- fmt.Errorf("error creating request: %w", err)
return
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/ndjson")
req.AddCookie(&http.Cookie{Name: "session_token", Value: fixToken})

// SearchTable performs the HTTP POST request to search in the inventory
func SearchTable(apiEndpoint, fixToken, workspaceID, searchStr string) (string, error) {
requestBody, err := json.Marshal(SearchRequest{
Query: searchStr,
Skip: 0,
Limit: 50,
Count: false,
Sort: []SortField{
{Path: "string", Direction: "asc"},
},
})
if err != nil {
return "", fmt.Errorf("error marshaling JSON: %w", err)
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
errs <- fmt.Errorf("error making HTTP request: %w", err)
return
}
defer resp.Body.Close()

url := fmt.Sprintf("%s/api/workspaces/%s/inventory/search/table", apiEndpoint, workspaceID)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
return "", fmt.Errorf("error creating request: %w", err)
}
if resp.StatusCode != 200 {
errs <- fmt.Errorf("search request failed with status code: %d", resp.StatusCode)
return
}

req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
req.AddCookie(&http.Cookie{Name: "session_token", Value: fixToken})
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
var result interface{}
if err := json.Unmarshal(scanner.Bytes(), &result); err != nil {
errs <- fmt.Errorf("error unmarshaling JSON: %w", err)
return
}
results <- result
}

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("error making HTTP request: %w", err)
}
defer resp.Body.Close()
if err := scanner.Err(); err != nil {
errs <- fmt.Errorf("error reading response body: %w", err)
return
}
}()

responseBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode != 200 {
return "", fmt.Errorf("search request failed with status code: %d, response: %s", resp.StatusCode, responseBody)
}
return string(responseBody), nil
return results, errs
}

0 comments on commit 465319a

Please sign in to comment.