Compare commits
No commits in common. "8f2131338d8f403709fba094f29124e9997d0f01" and "eee7e60a86554ae40a153e777cdf540d3e8b32a4" have entirely different histories.
8f2131338d
...
eee7e60a86
|
@ -38,7 +38,6 @@ func (a *Agent) Run(ctx context.Context) error {
|
||||||
client := client.New(a.serverURL, client.WithToken(token))
|
client := client.New(a.serverURL, client.WithToken(token))
|
||||||
|
|
||||||
ctx = withClient(ctx, client)
|
ctx = withClient(ctx, client)
|
||||||
ctx = withThumbprint(ctx, a.thumbprint)
|
|
||||||
|
|
||||||
tick := func() {
|
tick := func() {
|
||||||
logger.Debug(ctx, "registering agent")
|
logger.Debug(ctx, "registering agent")
|
||||||
|
|
|
@ -10,8 +10,7 @@ import (
|
||||||
type contextKey string
|
type contextKey string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
contextKeyClient contextKey = "client"
|
contextKeyClient contextKey = "client"
|
||||||
contextKeyThumbprint contextKey = "thumbprint"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func withClient(ctx context.Context, client *client.Client) context.Context {
|
func withClient(ctx context.Context, client *client.Client) context.Context {
|
||||||
|
@ -26,16 +25,3 @@ func Client(ctx context.Context) *client.Client {
|
||||||
|
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
func withThumbprint(ctx context.Context, thumbprint string) context.Context {
|
|
||||||
return context.WithValue(ctx, contextKeyThumbprint, thumbprint)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Thumbprint(ctx context.Context) string {
|
|
||||||
thumbprint, ok := ctx.Value(contextKeyThumbprint).(string)
|
|
||||||
if !ok {
|
|
||||||
panic(errors.New("could not retrieve thumbprint from context"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return thumbprint
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,138 +0,0 @@
|
||||||
package status
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"gitlab.com/wpetit/goweb/api"
|
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Status struct {
|
|
||||||
Agent *datastore.Agent
|
|
||||||
Connected bool
|
|
||||||
Claimed bool
|
|
||||||
Thumbprint string
|
|
||||||
ServerURL string
|
|
||||||
ClaimURL string
|
|
||||||
AgentURL string
|
|
||||||
AgentVersion string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
status *atomic.Value
|
|
||||||
server *atomic.Value
|
|
||||||
addr string
|
|
||||||
claimURL string
|
|
||||||
agentURL string
|
|
||||||
agentVersion string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name implements node.Controller.
|
|
||||||
func (c *Controller) Name() string {
|
|
||||||
return "status-controller"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconcile implements node.Controller.
|
|
||||||
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
|
||||||
cl := agent.Client(ctx)
|
|
||||||
thumbprint := agent.Thumbprint(ctx)
|
|
||||||
|
|
||||||
connected := true
|
|
||||||
|
|
||||||
agent, err := cl.GetAgent(ctx, state.AgentID())
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(ctx, "could not get agent", logger.E(errors.WithStack(err)))
|
|
||||||
var apiErr *api.Error
|
|
||||||
if errors.As(err, &apiErr) {
|
|
||||||
switch apiErr.Code {
|
|
||||||
case api.ErrCodeForbidden:
|
|
||||||
// Contact is ok but agent may be not claimed yet
|
|
||||||
default:
|
|
||||||
connected = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
connected = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
claimed := agent != nil && agent.TenantID != nil
|
|
||||||
var agentID datastore.AgentID
|
|
||||||
if agent != nil {
|
|
||||||
agentID = agent.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
c.status.Store(Status{
|
|
||||||
Agent: agent,
|
|
||||||
Connected: connected,
|
|
||||||
Claimed: claimed,
|
|
||||||
Thumbprint: thumbprint,
|
|
||||||
ServerURL: cl.ServerURL(),
|
|
||||||
ClaimURL: fmt.Sprintf(c.claimURL, thumbprint),
|
|
||||||
AgentURL: fmt.Sprintf(c.agentURL, agentID),
|
|
||||||
AgentVersion: c.agentVersion,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := c.startServer(ctx); err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) startServer(ctx context.Context) error {
|
|
||||||
server := c.getServer()
|
|
||||||
if server != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
server = &http.Server{
|
|
||||||
Addr: c.addr,
|
|
||||||
Handler: &Handler{
|
|
||||||
status: c.status,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer c.setServer(nil)
|
|
||||||
|
|
||||||
if err := server.ListenAndServe(); err != nil {
|
|
||||||
logger.Error(ctx, "could not start server", logger.E(errors.WithStack(err)))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
c.setServer(server)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) setServer(s *http.Server) {
|
|
||||||
c.server.Store(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) getServer() *http.Server {
|
|
||||||
server, ok := c.server.Load().(*http.Server)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return server
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController(addr string, claimURL string, agentURL string, agentVersion string) *Controller {
|
|
||||||
return &Controller{
|
|
||||||
addr: addr,
|
|
||||||
claimURL: claimURL,
|
|
||||||
agentURL: agentURL,
|
|
||||||
agentVersion: agentVersion,
|
|
||||||
status: &atomic.Value{},
|
|
||||||
server: &atomic.Value{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ agent.Controller = &Controller{}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package status
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
"html/template"
|
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed templates/*.gotpl
|
|
||||||
var templates embed.FS
|
|
||||||
|
|
||||||
//go:embed public/*
|
|
||||||
var public embed.FS
|
|
||||||
|
|
||||||
type Handler struct {
|
|
||||||
status *atomic.Value
|
|
||||||
|
|
||||||
public http.Handler
|
|
||||||
templates *template.Template
|
|
||||||
|
|
||||||
init sync.Once
|
|
||||||
initErr error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServeHTTP implements http.Handler.
|
|
||||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
h.init.Do(func() {
|
|
||||||
root, err := fs.Sub(public, "public")
|
|
||||||
if err != nil {
|
|
||||||
h.initErr = errors.WithStack(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.public = http.FileServer(http.FS(root))
|
|
||||||
|
|
||||||
tmpl, err := template.ParseFS(templates, "templates/*.gotpl")
|
|
||||||
if err != nil {
|
|
||||||
h.initErr = errors.WithStack(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.templates = tmpl
|
|
||||||
})
|
|
||||||
if h.initErr != nil {
|
|
||||||
logger.Error(r.Context(), "could not initialize handler", logger.E(h.initErr))
|
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r.URL.Path {
|
|
||||||
case "/":
|
|
||||||
h.serveIndex(w, r)
|
|
||||||
default:
|
|
||||||
h.public.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) serveIndex(w http.ResponseWriter, r *http.Request) {
|
|
||||||
data := h.status.Load()
|
|
||||||
|
|
||||||
if err := h.templates.ExecuteTemplate(w, "index.html.gotpl", data); err != nil {
|
|
||||||
logger.Error(r.Context(), "could not render template", logger.E(errors.WithStack(err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ http.Handler = &Handler{}
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
File diff suppressed because one or more lines are too long
|
@ -1,145 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="icon" type="image/x-icon" href="logo.png">
|
|
||||||
<title>Status | Emissary Agent</title>
|
|
||||||
<link rel="stylesheet" href="bulma-0.9.4.min.css">
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
background-color: #f7f7f7f7;
|
|
||||||
}
|
|
||||||
.logo {
|
|
||||||
left: 50%;
|
|
||||||
position: absolute;
|
|
||||||
margin-left: -40px;
|
|
||||||
width: 100px;
|
|
||||||
margin-top: -120px
|
|
||||||
}
|
|
||||||
.card {
|
|
||||||
position:relative;
|
|
||||||
padding-top: 70px;
|
|
||||||
margin-top: 70px;
|
|
||||||
}
|
|
||||||
#qrcode {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
{{if or .Connected ( not .Claimed ) }}
|
|
||||||
<script type="text/javascript" src="qrcode.min.js"></script>
|
|
||||||
{{ end }}
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<section class="section">
|
|
||||||
<div class="container">
|
|
||||||
<div class="column">
|
|
||||||
<div class="has-text-centered">
|
|
||||||
<h1 class="title is-size-1 ">Emissary</h1>
|
|
||||||
<h2 class="subtitle is-size-4">Agent Status</h2>
|
|
||||||
</div>
|
|
||||||
<div class="box card">
|
|
||||||
<img class="logo" src="logo.png" />
|
|
||||||
<div class="overflow:hidden">
|
|
||||||
<div class="level is-mobile" style="margin-top:-50px">
|
|
||||||
<div class="level-left">
|
|
||||||
<div class="level-item is-size-4-tablet is-size-7-mobile">
|
|
||||||
<strong class="mr-2">Connected:</strong>{{if .Connected }}<span class="has-text-success">✔</span>{{ else }}<span class="has-text-danger">✕</span>{{ end }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="level-right">
|
|
||||||
<div class="level-item is-size-4-tablet is-size-7-mobile">
|
|
||||||
<strong class="mr-2">Claimed:</strong>{{if .Claimed }}<span class="has-text-success">✔</span>{{ else }}<span class="has-text-warning">✕</span>{{ end }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{ if and .Connected ( not .Claimed ) }}
|
|
||||||
<h3 class="is-size-3 mt-4">Claim your agent</h3>
|
|
||||||
<p class="has-text-centered">
|
|
||||||
You can claim your agent by clicking the following link:<br />
|
|
||||||
<a class="button is-link is-medium mt-3" href="{{ .ClaimURL }}" target="_blank" rel="nofollow">Claim me</a><br />
|
|
||||||
</p>
|
|
||||||
<p class="has-text-centered mt-3">
|
|
||||||
You can also scan the following QRCode:
|
|
||||||
<div id="qrcode" class="mt-3" data-claim-url="{{ .ClaimURL }}"></div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
(function() {
|
|
||||||
const qrCodeElement = document.getElementById("qrcode");
|
|
||||||
const claimUrl = qrCodeElement.dataset.claimUrl;
|
|
||||||
new QRCode(qrCodeElement, claimUrl);
|
|
||||||
}())
|
|
||||||
</script>
|
|
||||||
</p>
|
|
||||||
{{ end }}
|
|
||||||
{{ if and .Connected .Claimed }}
|
|
||||||
<h3 class="is-size-3 mt-4">Manage your agent</h3>
|
|
||||||
<p class="has-text-centered">
|
|
||||||
You can manage your agent by clicking the following link:<br />
|
|
||||||
<a class="button is-link is-medium mt-3" href="{{ .AgentURL }}" target="_blank" rel="nofollow">Manage me</a><br />
|
|
||||||
</p>
|
|
||||||
<p class="has-text-centered mt-3">
|
|
||||||
You can also scan the following QRCode:
|
|
||||||
<div id="qrcode" class="mt-3" data-agent-url="{{ .AgentURL }}"></div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
(function() {
|
|
||||||
const qrCodeElement = document.getElementById("qrcode");
|
|
||||||
const agentUrl = qrCodeElement.dataset.agentUrl;
|
|
||||||
new QRCode(qrCodeElement, agentUrl);
|
|
||||||
}())
|
|
||||||
</script>
|
|
||||||
</p>
|
|
||||||
{{ end }}
|
|
||||||
<h3 class="is-size-3 mt-4">Informations</h3>
|
|
||||||
<div class="table-container">
|
|
||||||
<table class="table is-fullwidth">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Attribute</th>
|
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>Thumbprint</td>
|
|
||||||
<td><code>{{ .Thumbprint }}</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Agent ID</td>
|
|
||||||
<td><code>{{ if .Agent }}{{ .Agent.ID }}{{ else }}unknown{{end}}</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Agent Label</td>
|
|
||||||
<td><code>{{ with .Agent }}{{ if .Label }}{{ .Label }}{{ else }}empty{{end}}{{ else }}unknown{{end}}</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Last server contact</td>
|
|
||||||
<td><code>{{ if .Agent }}{{ .Agent.ContactedAt }}{{ else }}unknown{{end}}</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Server URL</td>
|
|
||||||
<td><code>{{ .ServerURL }}</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Claim URL</td>
|
|
||||||
<td><code>{{ .ClaimURL }}</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Agent URL</td>
|
|
||||||
<td><code>{{ if .Agent }}{{ .AgentURL }}{{ else }}unknown{{end}}</code></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Agent version</td>
|
|
||||||
<td><code>{{ .AgentVersion }}</code></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/persistence"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/persistence"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/proxy"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/proxy"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/spec"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/spec"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/status"
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/buildinfo"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/buildinfo"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/shell"
|
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/shell"
|
||||||
|
@ -95,15 +94,6 @@ func RunCommand() *cli.Command {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctrlConf.Status.Enabled {
|
|
||||||
controllers = append(controllers, status.NewController(
|
|
||||||
string(ctrlConf.Status.Address),
|
|
||||||
string(ctrlConf.Status.ClaimURL),
|
|
||||||
string(ctrlConf.Status.AgentURL),
|
|
||||||
string(ctx.String("projectVersion")),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := jwk.LoadOrGenerate(string(conf.Agent.PrivateKeyPath), jwk.DefaultKeySize)
|
key, err := jwk.LoadOrGenerate(string(conf.Agent.PrivateKeyPath), jwk.DefaultKeySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
|
|
|
@ -24,7 +24,6 @@ type ControllersConfig struct {
|
||||||
App AppControllerConfig `yaml:"app"`
|
App AppControllerConfig `yaml:"app"`
|
||||||
SysUpgrade SysUpgradeControllerConfig `yaml:"sysupgrade"`
|
SysUpgrade SysUpgradeControllerConfig `yaml:"sysupgrade"`
|
||||||
MDNS MDNSControllerConfig `yaml:"mdns"`
|
MDNS MDNSControllerConfig `yaml:"mdns"`
|
||||||
Status StatusControllerConfig `yaml:"status"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PersistenceControllerConfig struct {
|
type PersistenceControllerConfig struct {
|
||||||
|
@ -61,13 +60,6 @@ type MDNSControllerConfig struct {
|
||||||
Enabled InterpolatedBool `yaml:"enabled"`
|
Enabled InterpolatedBool `yaml:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatusControllerConfig struct {
|
|
||||||
Enabled InterpolatedBool `yaml:"enabled"`
|
|
||||||
Address InterpolatedString `yaml:"address"`
|
|
||||||
ClaimURL InterpolatedString `yaml:"claimURL"`
|
|
||||||
AgentURL InterpolatedString `yaml:"agentURL"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultAgentConfig() AgentConfig {
|
func NewDefaultAgentConfig() AgentConfig {
|
||||||
return AgentConfig{
|
return AgentConfig{
|
||||||
ServerURL: "http://127.0.0.1:3000",
|
ServerURL: "http://127.0.0.1:3000",
|
||||||
|
@ -102,12 +94,6 @@ func NewDefaultAgentConfig() AgentConfig {
|
||||||
MDNS: MDNSControllerConfig{
|
MDNS: MDNSControllerConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
Status: StatusControllerConfig{
|
|
||||||
Enabled: true,
|
|
||||||
Address: ":42521",
|
|
||||||
ClaimURL: "http://localhost:3001/claim/%s",
|
|
||||||
AgentURL: "http://localhost:3001/agents/%v",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Collectors: []ShellCollectorConfig{
|
Collectors: []ShellCollectorConfig{
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,16 +62,6 @@ agent:
|
||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
- source /etc/openwrt_release && echo "$DISTRIB_ID-$DISTRIB_RELEASE-$DISTRIB_REVISION"
|
- source /etc/openwrt_release && echo "$DISTRIB_ID-$DISTRIB_RELEASE-$DISTRIB_REVISION"
|
||||||
|
|
||||||
# Status controller configuration
|
|
||||||
status:
|
|
||||||
enabled: true
|
|
||||||
# Status page listening address
|
|
||||||
address: :42521
|
|
||||||
# Agent claim URL template (see Emissary HQ)
|
|
||||||
claimURL: http://127.0.0.1:3001/claim/%v
|
|
||||||
# Agent URL template (see Emissary HQ)
|
|
||||||
agentURL: http://127.0.0.1:3001/agents/%v
|
|
||||||
|
|
||||||
# Collectors configuration
|
# Collectors configuration
|
||||||
collectors:
|
collectors:
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
**/*.go
|
**/*.go
|
||||||
internal/**/*.json
|
internal/**/*.json
|
||||||
**/*.gotpl
|
|
||||||
modd.conf
|
modd.conf
|
||||||
tmp/config.yml
|
tmp/config.yml
|
||||||
.env {
|
.env {
|
||||||
|
|
|
@ -18,10 +18,6 @@ type Client struct {
|
||||||
serverURL string
|
serverURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ServerURL() string {
|
|
||||||
return c.serverURL
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) apiGet(ctx context.Context, path string, result any, funcs ...OptionFunc) error {
|
func (c *Client) apiGet(ctx context.Context, path string, result any, funcs ...OptionFunc) error {
|
||||||
if err := c.apiDo(ctx, http.MethodGet, path, nil, result, funcs...); err != nil {
|
if err := c.apiDo(ctx, http.MethodGet, path, nil, result, funcs...); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
|
|
Loading…
Reference in New Issue