-
Notifications
You must be signed in to change notification settings - Fork 1
initial version #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
radulucut
wants to merge
10
commits into
jsdelivr:master
Choose a base branch
from
radulucut:v0.1.0
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 7 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
fc40011
initial version
radulucut 73b8533
add test workflow, set min version 1.23
radulucut cd186f5
implement suggestions
radulucut 29b79de
fix issues, refactor
radulucut df9d004
auth fixes and doc updates
radulucut 9e8c9ec
implement suggestions
radulucut 03159e9
remove auth, add probes and update docs
radulucut c3045b9
suggestions
radulucut acd26dd
format examples
radulucut d0192a8
fix link
radulucut File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| name: Tests | ||
| on: | ||
| pull_request: | ||
| branches: [master] | ||
|
|
||
| push: | ||
| branches: [master] | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| go: ["1.24"] | ||
| os: [ubuntu-latest] | ||
| name: "Test" | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| - name: Setup go | ||
| uses: actions/setup-go@v6 | ||
| with: | ||
| go-version: ${{ matrix.go }} | ||
| - name: Run tests | ||
| run: go test ./... -v -race -timeout 30s |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| bin/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,150 @@ | ||
| # globalping-go | ||
| # Globalping Go API Client | ||
|
|
||
| The official Go client for the [Globalping API](https://globalping.io/docs/api.globalping.io). | ||
|
|
||
| ## Installation | ||
|
|
||
| To install the client, run the following command: | ||
|
|
||
| ```bash | ||
| go get github.com/jsdelivr/globalping-go | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| To use the client, import it into your Go code: | ||
|
|
||
| ```go | ||
| import "github.com/jsdelivr/globalping-go" | ||
|
|
||
| func main() { | ||
| client := globalping.NewClient(globalping.Config{ | ||
| AuthToken: "<your_access_token>", // Optional | ||
| }) | ||
| } | ||
| ``` | ||
|
|
||
| ### Create Measurement | ||
|
|
||
| Creates a new measurement with the set parameters. The measurement runs asynchronously, and you can retrieve its current state using GetMeasurement() or wait for its final state using AwaitMeasurement(). | ||
|
|
||
| ```go | ||
| o := &globalping.MeasurementCreate{ | ||
| Type: globalping.MeasurementTypePing, | ||
| Target: "google.com", | ||
| Limit: 1, | ||
| Locations: []globalping.Locations{ | ||
| { | ||
| Magic: "world", | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| res, err := client.CreateMeasurement(ctx, o) | ||
| if err != nil { | ||
| fmt.Println(err) | ||
| return | ||
| } | ||
| ``` | ||
|
|
||
| ### Get a measurement | ||
|
|
||
| Returns the current state of the measurement. | ||
|
|
||
| ```go | ||
| measurement, err := client.GetMeasurement(ctx, res.ID) | ||
| if err != nil { | ||
| fmt.Println(err) | ||
| return | ||
| } | ||
|
|
||
| fmt.Printf("%+v\n", measurement) | ||
| ``` | ||
|
|
||
| ### Await a measurement | ||
|
|
||
| Similar to GetMeasurement(), but keeps pooling the API until the measurement is finished, and returns its final state. | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```go | ||
| measurement, err := client.AwaitMeasurement(ctx, res.ID) | ||
| if err != nil { | ||
| fmt.Println(err) | ||
| return | ||
| } | ||
|
|
||
| fmt.Printf("%+v\n", measurement) | ||
| ``` | ||
|
|
||
| ### Get raw measurement bytes | ||
|
|
||
| Returns the raw measurement bytes. | ||
|
|
||
| ```go | ||
| b, err := client.GetMeasurementRaw(ctx, res.ID) | ||
| if err != nil { | ||
| fmt.Println(err) | ||
| return | ||
| } | ||
| ``` | ||
|
|
||
| ### Probes | ||
|
|
||
| Returns a list of all probes currently online and their metadata, such as location and assigned tags. | ||
|
|
||
| ```go | ||
| probes, err := client.Probes(ctx) | ||
| if err != nil { | ||
| fmt.Println(err) | ||
| return | ||
| } | ||
|
|
||
| fmt.Printf("%+v\n", probes) | ||
| ``` | ||
|
|
||
| ### Get rate limits | ||
|
|
||
| Returns rate limits for the current user (if authenticated) or IP address (if not authenticated). | ||
|
|
||
| ```go | ||
| limits, err := client.Limits(ctx) | ||
| if err != nil { | ||
| fmt.Println(err) | ||
| return | ||
| } | ||
|
|
||
| fmt.Printf("%+v\n", limits) | ||
| ``` | ||
|
|
||
| ### Error handling | ||
|
|
||
| API errors are returned as `*globalping.MeasurementError` instances. You can access the error code and headers using the `StatusCode` and `Header` fields. | ||
|
|
||
| ```go | ||
| measurement, err := client.GetMeasurement(ctx, res.ID) | ||
| if err != nil { | ||
| if measurementErr, ok := err.(*globalping.MeasurementError); ok { | ||
| // measurementErr.StatusCode | ||
| // measurementErr.Header | ||
| } else { | ||
| fmt.Println(err) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Advanced configuration | ||
|
|
||
| `AuthToken` | ||
|
|
||
| A user authentication token obtained from https://dash.globalping.io or via OAuth (currently available only to official Globalping apps). | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| `UserAgent` | ||
|
|
||
| Refers to this library by default. If you build another open-source project based on this library, you should override this value to point to your project instead. | ||
|
|
||
| `CacheExpireSeconds` | ||
|
|
||
| Specifies the expiration time for cached measurements in seconds. 0 means no expiration. | ||
|
|
||
| `HTTPClient` | ||
|
|
||
| Custom HTTP client to use for requests. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| package globalping | ||
|
|
||
| import "time" | ||
|
|
||
| type cacheEntry struct { | ||
| ETag string | ||
| Data []byte | ||
| ExpireAt int64 // Unix timestamp | ||
| } | ||
|
|
||
| func (c *client) CacheClean() { | ||
| c.cleanupCache() | ||
| } | ||
|
|
||
| func (c *client) CachePurge() { | ||
| c.mu.Lock() | ||
| defer c.mu.Unlock() | ||
| c.cache = map[string]*cacheEntry{} | ||
| } | ||
|
|
||
| func (c *client) getETag(id string) string { | ||
| c.mu.RLock() | ||
| defer c.mu.RUnlock() | ||
| e, ok := c.cache[id] | ||
| if !ok { | ||
| return "" | ||
| } | ||
| if e.ExpireAt > 0 && e.ExpireAt < time.Now().Unix() { | ||
| return "" | ||
| } | ||
| return e.ETag | ||
| } | ||
|
|
||
| func (c *client) getCachedResponse(id string) []byte { | ||
| c.mu.RLock() | ||
| defer c.mu.RUnlock() | ||
| e, ok := c.cache[id] | ||
| if !ok { | ||
| return nil | ||
| } | ||
| if e.ExpireAt > 0 && e.ExpireAt < time.Now().Unix() { | ||
| return nil | ||
| } | ||
| return e.Data | ||
| } | ||
|
|
||
| func (c *client) cacheResponse(id string, etag string, resp []byte) { | ||
| c.mu.Lock() | ||
| defer c.mu.Unlock() | ||
| var expires int64 | ||
| if c.cacheExpireSeconds != 0 { | ||
| expires = time.Now().Unix() + c.cacheExpireSeconds | ||
| } | ||
| e, ok := c.cache[id] | ||
| if ok { | ||
| e.ETag = etag | ||
| e.Data = resp | ||
| e.ExpireAt = expires | ||
| } else { | ||
| c.cache[id] = &cacheEntry{ | ||
| ETag: etag, | ||
| Data: resp, | ||
| ExpireAt: expires, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func (c *client) cleanupCache() { | ||
| c.mu.Lock() | ||
| defer c.mu.Unlock() | ||
| now := time.Now().Unix() | ||
| for k, v := range c.cache { | ||
| if v.ExpireAt > 0 && v.ExpireAt < now { | ||
| delete(c.cache, k) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| package globalping | ||
|
|
||
| import ( | ||
| "context" | ||
| "net/http" | ||
| "sync" | ||
| "time" | ||
| ) | ||
|
|
||
| var ( | ||
| APIURL = "https://api.globalping.io/v1" | ||
| ) | ||
|
|
||
| type Client interface { | ||
| // Creates a new measurement with parameters set in the request body. The measurement runs asynchronously and you can retrieve its current state at the URL returned in the Location header. | ||
| // | ||
| // https://globalping.io/docs/api.globalping.io#post-/v1/measurements | ||
| CreateMeasurement(ctx context.Context, measurement *MeasurementCreate) (*MeasurementCreateResponse, error) | ||
|
|
||
| // Returns the status and results of an existing measurement. Measurements are typically available for up to 7 days after creation. | ||
| // | ||
| // https://globalping.io/docs/api.globalping.io#get-/v1/measurements/-id- | ||
| GetMeasurement(ctx context.Context, id string) (*Measurement, error) | ||
|
|
||
| // Waits for the measurement to complete and returns the results. | ||
| // | ||
| // https://globalping.io/docs/api.globalping.io#get-/v1/measurements/-id- | ||
| AwaitMeasurement(ctx context.Context, id string) (*Measurement, error) | ||
|
|
||
| // Returns the status and results of an existing measurement. Measurements are typically available for up to 7 days after creation. | ||
| // | ||
| // https://globalping.io/docs/api.globalping.io#get-/v1/measurements/-id- | ||
| GetMeasurementRaw(ctx context.Context, id string) ([]byte, error) | ||
|
|
||
| // Returns the rate limits for the current user or IP address. | ||
| // | ||
| // https://globalping.io/docs/api.globalping.io#get-/v1/limits | ||
| Limits(ctx context.Context) (*LimitsResponse, error) | ||
|
|
||
| // Returns a list of all probes currently online and their metadata, such as location and assigned tags. | ||
| // | ||
| // https://globalping.io/docs/api.globalping.io#get-/v1/probes | ||
| Probes(ctx context.Context) (*ProbesResponse, error) | ||
|
|
||
| // Clears the expired cached entries. | ||
| CacheClean() | ||
|
|
||
| // Removes all cached entries regardless of expiration. | ||
| CachePurge() | ||
| } | ||
|
|
||
| type Config struct { | ||
| AuthToken string // Your GlobalPing API access token. Optional. | ||
| UserAgent string // User agent string for API requests. Optional. | ||
| CacheExpireSeconds int64 // Cache entry expiration time in seconds. 0 means no expiration. | ||
|
|
||
| HTTPClient *http.Client // If set, this client will be used for API requests. Optional. | ||
| } | ||
|
|
||
| type client struct { | ||
| mu sync.RWMutex | ||
| http *http.Client | ||
| cache map[string]*cacheEntry | ||
|
|
||
| cacheExpireSeconds int64 | ||
| userAgent string | ||
| authToken string | ||
| } | ||
|
|
||
| // Creates a new client with the given configuration. | ||
| // | ||
| // Note: The client caches API responses. | ||
| // Set CacheExpireSeconds to configure the entry expiration and use CacheClean to clear the expired entries when reusing the client. | ||
| func NewClient(config Config) Client { | ||
| c := &client{ | ||
| mu: sync.RWMutex{}, | ||
| userAgent: config.UserAgent, | ||
| authToken: config.AuthToken, | ||
| cache: map[string]*cacheEntry{}, | ||
| cacheExpireSeconds: config.CacheExpireSeconds, | ||
| } | ||
|
|
||
| if config.UserAgent == "" { | ||
| c.userAgent = "jsdelivr/globalping-go" | ||
| } | ||
|
|
||
| if config.HTTPClient != nil { | ||
| c.http = config.HTTPClient | ||
| } else { | ||
| c.http = &http.Client{ | ||
| Timeout: 30 * time.Second, | ||
| } | ||
| } | ||
|
|
||
| return c | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| module github.com/jsdelivr/globalping-go | ||
|
|
||
| go 1.24.0 | ||
|
|
||
| require ( | ||
| github.com/andybalholm/brotli v1.2.0 | ||
| github.com/stretchr/testify v1.11.1 | ||
| ) | ||
|
|
||
| require ( | ||
| github.com/davecgh/go-spew v1.1.1 // indirect | ||
| github.com/kr/pretty v0.3.1 // indirect | ||
| github.com/pmezard/go-difflib v1.0.0 // indirect | ||
| github.com/rogpeppe/go-internal v1.14.1 // indirect | ||
| gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect | ||
| gopkg.in/yaml.v3 v3.0.1 // indirect | ||
| ) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.