Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/cli. OpenStatus CLI www.openstatus.dev
Something went wrong. Try again.
Go
at refactor-sdk
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491package monitors
import ( "context" "encoding/json" "fmt" "net/http"
monitorv1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/monitor/v1" "buf.build/gen/go/openstatus/api/connectrpc/gosimple/openstatus/monitor/v1/monitorv1connect" "connectrpc.com/connect" "github.com/openstatusHQ/cli/internal/config" "github.com/urfave/cli/v3")
// APIBaseURL is the base URL for the OpenStatus APIconst APIBaseURL = "https://api.openstatus.dev/v1"
// ConnectBaseURL is the base URL for the Connect RPC APIconst ConnectBaseURL = "https://api.openstatus.dev/rpc"
// NewAuthInterceptor creates an interceptor that adds the API key to all requestsfunc NewAuthInterceptor(apiKey string) connect.UnaryInterceptorFunc { return func(next connect.UnaryFunc) connect.UnaryFunc { return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) { req.Header().Set("x-openstatus-key", apiKey) return next(ctx, req) } }}
// NewMonitorClient creates a new Monitor service client with authenticationfunc NewMonitorClient(apiKey string) monitorv1connect.MonitorServiceClient { return monitorv1connect.NewMonitorServiceClient( http.DefaultClient, ConnectBaseURL, connect.WithInterceptors(NewAuthInterceptor(apiKey)), connect.WithProtoJSON(), )}
// NewMonitorClientWithHTTPClient creates a new Monitor service client with a custom HTTP clientfunc NewMonitorClientWithHTTPClient(httpClient *http.Client, apiKey string) monitorv1connect.MonitorServiceClient { return monitorv1connect.NewMonitorServiceClient( httpClient, ConnectBaseURL, connect.WithInterceptors(NewAuthInterceptor(apiKey)), connect.WithProtoJSON(), )}
// Helper functions to convert SDK types to CLI display types
// periodicityToString converts SDK Periodicity enum to stringfunc periodicityToString(p monitorv1.Periodicity) string { switch p { case monitorv1.Periodicity_PERIODICITY_30S: return "30s" case monitorv1.Periodicity_PERIODICITY_1M: return "1m" case monitorv1.Periodicity_PERIODICITY_5M: return "5m" case monitorv1.Periodicity_PERIODICITY_10M: return "10m" case monitorv1.Periodicity_PERIODICITY_30M: return "30m" case monitorv1.Periodicity_PERIODICITY_1H: return "1h" default: return "unknown" }}
// httpMethodToString converts SDK HTTPMethod enum to stringfunc httpMethodToString(m monitorv1.HTTPMethod) string { switch m { case monitorv1.HTTPMethod_HTTP_METHOD_GET: return "GET" case monitorv1.HTTPMethod_HTTP_METHOD_POST: return "POST" case monitorv1.HTTPMethod_HTTP_METHOD_HEAD: return "HEAD" case monitorv1.HTTPMethod_HTTP_METHOD_PUT: return "PUT" case monitorv1.HTTPMethod_HTTP_METHOD_PATCH: return "PATCH" case monitorv1.HTTPMethod_HTTP_METHOD_DELETE: return "DELETE" case monitorv1.HTTPMethod_HTTP_METHOD_TRACE: return "TRACE" case monitorv1.HTTPMethod_HTTP_METHOD_CONNECT: return "CONNECT" case monitorv1.HTTPMethod_HTTP_METHOD_OPTIONS: return "OPTIONS" default: return "" }}
// regionToString converts SDK Region enum to stringfunc regionToString(r monitorv1.Region) string { switch r { case monitorv1.Region_REGION_FLY_AMS: return "ams" case monitorv1.Region_REGION_FLY_ARN: return "arn" case monitorv1.Region_REGION_FLY_BOM: return "bom" case monitorv1.Region_REGION_FLY_CDG: return "cdg" case monitorv1.Region_REGION_FLY_DFW: return "dfw" case monitorv1.Region_REGION_FLY_EWR: return "ewr" case monitorv1.Region_REGION_FLY_FRA: return "fra" case monitorv1.Region_REGION_FLY_GRU: return "gru" case monitorv1.Region_REGION_FLY_IAD: return "iad" case monitorv1.Region_REGION_FLY_JNB: return "jnb" case monitorv1.Region_REGION_FLY_LAX: return "lax" case monitorv1.Region_REGION_FLY_LHR: return "lhr" case monitorv1.Region_REGION_FLY_NRT: return "nrt" case monitorv1.Region_REGION_FLY_ORD: return "ord" case monitorv1.Region_REGION_FLY_SJC: return "sjc" case monitorv1.Region_REGION_FLY_SIN: return "sin" case monitorv1.Region_REGION_FLY_SYD: return "syd" case monitorv1.Region_REGION_FLY_YYZ: return "yyz" default: return r.String() }}
// regionsToStrings converts a slice of SDK Region enums to stringsfunc regionsToStrings(regions []monitorv1.Region) []string { result := make([]string, len(regions)) for i, r := range regions { result[i] = r.String() } return result}
// Inverse converter functions (config types → SDK types)
// stringToPeriodicity converts config.Frequency to SDK Periodicityfunc stringToPeriodicity(f config.Frequency) monitorv1.Periodicity { switch f { case config.The30S: return monitorv1.Periodicity_PERIODICITY_30S case config.The1M: return monitorv1.Periodicity_PERIODICITY_1M case config.The5M: return monitorv1.Periodicity_PERIODICITY_5M case config.The10M: return monitorv1.Periodicity_PERIODICITY_10M case config.The30M: return monitorv1.Periodicity_PERIODICITY_30M case config.The1H: return monitorv1.Periodicity_PERIODICITY_1H default: return monitorv1.Periodicity_PERIODICITY_10M }}
// stringToHTTPMethod converts config.Method to SDK HTTPMethodfunc stringToHTTPMethod(m config.Method) monitorv1.HTTPMethod { switch m { case config.Get: return monitorv1.HTTPMethod_HTTP_METHOD_GET case config.Post: return monitorv1.HTTPMethod_HTTP_METHOD_POST case config.Put: return monitorv1.HTTPMethod_HTTP_METHOD_PUT case config.Patch: return monitorv1.HTTPMethod_HTTP_METHOD_PATCH case config.Delete: return monitorv1.HTTPMethod_HTTP_METHOD_DELETE case config.Head: return monitorv1.HTTPMethod_HTTP_METHOD_HEAD case config.Options: return monitorv1.HTTPMethod_HTTP_METHOD_OPTIONS default: return monitorv1.HTTPMethod_HTTP_METHOD_GET }}
// stringToRegion converts config.Region to SDK Regionfunc stringToRegion(r config.Region) monitorv1.Region { switch r { case config.Ams: return monitorv1.Region_REGION_FLY_AMS case config.Arn: return monitorv1.Region_REGION_FLY_ARN case config.BOM: return monitorv1.Region_REGION_FLY_BOM case config.Cdg: return monitorv1.Region_REGION_FLY_CDG case config.Dfw: return monitorv1.Region_REGION_FLY_DFW case config.Ewr: return monitorv1.Region_REGION_FLY_EWR case config.Fra: return monitorv1.Region_REGION_FLY_FRA case config.Gru: return monitorv1.Region_REGION_FLY_GRU case config.Iad: return monitorv1.Region_REGION_FLY_IAD case config.Jnb: return monitorv1.Region_REGION_FLY_JNB case config.Lax: return monitorv1.Region_REGION_FLY_LAX case config.Lhr: return monitorv1.Region_REGION_FLY_LHR case config.Nrt: return monitorv1.Region_REGION_FLY_NRT case config.Ord: return monitorv1.Region_REGION_FLY_ORD case config.Sin: return monitorv1.Region_REGION_FLY_SIN case config.Sjc: return monitorv1.Region_REGION_FLY_SJC case config.Syd: return monitorv1.Region_REGION_FLY_SYD case config.Yyz: return monitorv1.Region_REGION_FLY_YYZ default: return monitorv1.Region_REGION_UNSPECIFIED }}
// stringsToRegions converts []config.Region to []monitorv1.Regionfunc stringsToRegions(regions []config.Region) []monitorv1.Region { result := make([]monitorv1.Region, len(regions)) for i, r := range regions { result[i] = stringToRegion(r) } return result}
// configCompareToNumberComparator converts config.Compare to NumberComparatorfunc configCompareToNumberComparator(c config.Compare) monitorv1.NumberComparator { switch c { case config.Eq: return monitorv1.NumberComparator_NUMBER_COMPARATOR_EQUAL case config.NotEq: return monitorv1.NumberComparator_NUMBER_COMPARATOR_NOT_EQUAL case config.Gt: return monitorv1.NumberComparator_NUMBER_COMPARATOR_GREATER_THAN case config.Gte: return monitorv1.NumberComparator_NUMBER_COMPARATOR_GREATER_THAN_OR_EQUAL case config.Lt: return monitorv1.NumberComparator_NUMBER_COMPARATOR_LESS_THAN case config.LTE: return monitorv1.NumberComparator_NUMBER_COMPARATOR_LESS_THAN_OR_EQUAL default: return monitorv1.NumberComparator_NUMBER_COMPARATOR_EQUAL }}
// configCompareToStringComparator converts config.Compare to StringComparatorfunc configCompareToStringComparator(c config.Compare) monitorv1.StringComparator { switch c { case config.Eq: return monitorv1.StringComparator_STRING_COMPARATOR_EQUAL case config.NotEq: return monitorv1.StringComparator_STRING_COMPARATOR_NOT_EQUAL case config.Contains: return monitorv1.StringComparator_STRING_COMPARATOR_CONTAINS case config.NotContains: return monitorv1.StringComparator_STRING_COMPARATOR_NOT_CONTAINS case config.Empty: return monitorv1.StringComparator_STRING_COMPARATOR_EMPTY case config.NotEmpty: return monitorv1.StringComparator_STRING_COMPARATOR_NOT_EMPTY case config.Gt: return monitorv1.StringComparator_STRING_COMPARATOR_GREATER_THAN case config.Gte: return monitorv1.StringComparator_STRING_COMPARATOR_GREATER_THAN_OR_EQUAL case config.Lt: return monitorv1.StringComparator_STRING_COMPARATOR_LESS_THAN case config.LTE: return monitorv1.StringComparator_STRING_COMPARATOR_LESS_THAN_OR_EQUAL default: return monitorv1.StringComparator_STRING_COMPARATOR_EQUAL }}
// Builder functions (config.Monitor → SDK monitor types)
// configToHTTPMonitor converts config.Monitor to SDK HTTPMonitorfunc configToHTTPMonitor(m config.Monitor) *monitorv1.HTTPMonitor { // Convert headers headers := make([]*monitorv1.Headers, 0, len(m.Request.Headers)) for k, v := range m.Request.Headers { headers = append(headers, &monitorv1.Headers{Key: k, Value: v}) }
// Convert assertions to separate types var statusCodeAssertions []*monitorv1.StatusCodeAssertion var bodyAssertions []*monitorv1.BodyAssertion var headerAssertions []*monitorv1.HeaderAssertion
for _, a := range m.Assertions { switch a.Kind { case config.StatusCode: var target int64 switch v := a.Target.(type) { case int: target = int64(v) case int64: target = v case float64: target = int64(v) } statusCodeAssertions = append(statusCodeAssertions, &monitorv1.StatusCodeAssertion{ Target: target, Comparator: configCompareToNumberComparator(a.Compare), }) case config.TextBody: target, _ := a.Target.(string) bodyAssertions = append(bodyAssertions, &monitorv1.BodyAssertion{ Target: target, Comparator: configCompareToStringComparator(a.Compare), }) case config.Header: target, _ := a.Target.(string) headerAssertions = append(headerAssertions, &monitorv1.HeaderAssertion{ Key: a.Key, Target: target, Comparator: configCompareToStringComparator(a.Compare), }) } }
monitor := &monitorv1.HTTPMonitor{ Name: m.Name, Description: m.Description, Url: m.Request.URL, Method: stringToHTTPMethod(m.Request.Method), Body: m.Request.Body, Periodicity: stringToPeriodicity(m.Frequency), Active: m.Active, Public: m.Public, Regions: stringsToRegions(m.Regions), Timeout: m.Timeout, Retry: m.Retry, Headers: headers, StatusCodeAssertions: statusCodeAssertions, BodyAssertions: bodyAssertions, HeaderAssertions: headerAssertions, }
if m.DegradedAfter > 0 { monitor.DegradedAt = &m.DegradedAfter }
return monitor}
// configToTCPMonitor converts config.Monitor to SDK TCPMonitorfunc configToTCPMonitor(m config.Monitor) *monitorv1.TCPMonitor { monitor := &monitorv1.TCPMonitor{ Name: m.Name, Description: m.Description, Uri: fmt.Sprintf("%s:%d", m.Request.Host, m.Request.Port), Periodicity: stringToPeriodicity(m.Frequency), Active: m.Active, Public: m.Public, Regions: stringsToRegions(m.Regions), Timeout: m.Timeout, Retry: m.Retry, }
if m.DegradedAfter > 0 { monitor.DegradedAt = &m.DegradedAfter }
return monitor}
type Monitor struct { ID int `json:"id"` Name string `json:"name"` URL string `json:"url"` Periodicity string `json:"periodicity"` Description string `json:"description"` Method string `json:"method"` Regions []string `json:"regions"` Active bool `json:"active"` Public bool `json:"public"` Timeout int `json:"timeout"` DegradedAfter int `json:"degraded_after,omitempty"` Body string `json:"body"` Headers []Header `json:"headers,omitempty"` Assertions []Assertion `json:"assertions,omitempty"` Retry int `json:"retry"` JobType string `json:"jobType"`}
type Header struct { Key string `json:"key"` Value string `json:"value"`}
type Assertion struct { Type string `json:"type"` Compare string `json:"compare"` Key string `json:"key"` Target any `json:"target"`}
type Timing struct { DnsStart int64 `json:"dnsStart"` DnsDone int64 `json:"dnsDone"` ConnectStart int64 `json:"connectStart"` ConnectDone int64 `json:"connectDone"` TlsHandshakeStart int64 `json:"tlsHandshakeStart"` TlsHandshakeDone int64 `json:"tlsHandshakeDone"` FirstByteStart int64 `json:"firstByteStart"` FirstByteDone int64 `json:"firstByteDone"` TransferStart int64 `json:"transferStart"` TransferDone int64 `json:"transferDone"`}
type MonitorTriggerResponse struct { ResultId int `json:"resultId"`}
type TriggerResultResponse struct { MonitorId string `json:"monitorId"` Url string `json:"url"` Error bool `json:"error"` Region string `json:"region"` Timestamp int `json:"timestamp"` Latency int `json:"latency"` StatusCode int `json:"statusCode"` Timing Timing `json:"timing"`}
type RunResult struct { JobType string `json:"jobType"` Region string `json:"region"` Message json.RawMessage Timestamp int64 `json:"timestamp"` Latency int64 `json:"latency"`}
type HTTPRunResult struct { Headers map[string]string `json:"headers,omitempty"` Body string `json:"body,omitempty"` Error string `json:"error,omitempty"` Status int `json:"status,omitempty"` Timing Timing `json:"timing"`}
type TCPRunResult struct { ErrorMessage string `json:"errorMessage"` Timing struct { TCPStart int64 `json:"tcpStart"` TCPDone int64 `json:"tcpDone"` } `json:"timing"`}
func MonitorsCmd() *cli.Command { monitorsCmd := cli.Command{ Name: "monitors", Usage: "Manage your monitors",
Commands: []*cli.Command{ GetMonitorsApplyCmd(), GetMonitorCreateCmd(), GetMonitorDeleteCmd(), GetMonitorImportCmd(), GetMonitorInfoCmd(), GetMonitorsListCmd(), GetMonitorsTriggerCmd(), }, } return &monitorsCmd}