func New(cl *http.Client, opts ...Option) (*Client, error) {
	client := &Client{
		cl:      cl,
		baseURL: urlutil.CloneURL(DefaultServerURL),
	}
	for _, opt := range opts {
		opt.apply(client)
	}
	return client, nil
}
New creates a new Client with the given options.
package api
import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"path"
	"go.thethings.network/lorawan-stack/v3/pkg/log"
	urlutil "go.thethings.network/lorawan-stack/v3/pkg/util/url"
)
type Option interface {
	apply(*Client)
}
type OptionFunc func(*Client)
func (f OptionFunc) apply(c *Client) { f(c) }
type Client struct {
	token   string
	baseURL *url.URL
	cl      *http.Client
}
const (
	contentType      = "application/json"
	defaultServerURL = "https://gls.loracloud.com"
	basePath         = "/api"
)
var DefaultServerURL = func() *url.URL {
	parsed, err := url.Parse(defaultServerURL)
	if err != nil {
		panic(fmt.Sprintf("loragls: failed to parse base URL: %v", err))
	}
	return parsed
}()
func (c *Client) newRequest(ctx context.Context, method, version, category, operation string, body io.Reader) (*http.Request, error) {
	u := urlutil.CloneURL(c.baseURL)
	u.Path = path.Join(basePath, version, category, operation)
	req, err := http.NewRequestWithContext(ctx, method, u.String(), body)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", contentType)
	if c.token != "" {
		req.Header.Set("Ocp-Apim-Subscription-Key", c.token)
	}
	return req, nil
}
func (c *Client) Do(ctx context.Context, method, version, category, operation string, body interface{}) (*http.Response, error) {
	buffer := bytes.NewBuffer(nil)
	if err := json.NewEncoder(buffer).Encode(body); err != nil {
		return nil, err
	}
	log.FromContext(ctx).WithFields(log.Fields(
		"method", method,
		"version", version,
		"category", category,
		"operation", operation,
		"body", buffer.String(),
	)).Debug("Run GLS request")
	req, err := c.newRequest(ctx, method, version, category, operation, buffer)
	if err != nil {
		return nil, err
	}
	return c.cl.Do(req)
}
func WithToken(token string) Option {
	return OptionFunc(func(c *Client) {
		c.token = token
	})
}
func WithBaseURL(baseURL *url.URL) Option {
	return OptionFunc(func(c *Client) {
		c.baseURL = baseURL
	})
}
func (c *Client) SolveSingleFrame(ctx context.Context, request *SingleFrameRequest) (*ExtendedLocationSolverResponse, error) {
	resp, err := c.Do(ctx, http.MethodPost, "v3", "solve", "singleframe", request)
	if err != nil {
		return nil, err
	}
	response := &ExtendedLocationSolverResponse{}
	err = parse(&response, resp)
	if err != nil {
		return nil, err
	}
	return response, nil
}
func (c *Client) SolveMultiFrame(ctx context.Context, request *MultiFrameRequest) (*ExtendedLocationSolverResponse, error) {
	resp, err := c.Do(ctx, http.MethodPost, "v3", "solve", "multiframe", request)
	if err != nil {
		return nil, err
	}
	response := &ExtendedLocationSolverResponse{}
	err = parse(&response, resp)
	if err != nil {
		return nil, err
	}
	return response, nil
}
func (c *Client) SolveGNSS(ctx context.Context, request *GNSSRequest) (*ExtendedGNSSLocationSolverResponse, error) {
	resp, err := c.Do(ctx, http.MethodPost, "v3", "solve", "gnss_lr1110_singleframe", request)
	if err != nil {
		return nil, err
	}
	response := &ExtendedGNSSLocationSolverResponse{}
	err = parse(&response, resp)
	if err != nil {
		return nil, err
	}
	return response, nil
}
func (c *Client) SolveWiFi(ctx context.Context, request *WiFiRequest) (*ExtendedWiFiLocationSolverResponse, error) {
	resp, err := c.Do(ctx, http.MethodPost, "v2", "", "loraWifi", request)
	if err != nil {
		return nil, err
	}
	response := &ExtendedWiFiLocationSolverResponse{}
	err = parse(&response, resp)
	if err != nil {
		return nil, err
	}
	return response, nil
}