mirror of
https://github.com/fosrl/olm.git
synced 2026-03-04 01:36:47 +00:00
Import copied libs
This commit is contained in:
1
go.mod
1
go.mod
@@ -7,6 +7,7 @@ toolchain go1.23.2
|
|||||||
require golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
require golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/fosrl/newt v0.0.0-20250215225251-76503f3f2cd8 // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.3 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -1,3 +1,5 @@
|
|||||||
|
github.com/fosrl/newt v0.0.0-20250215225251-76503f3f2cd8 h1:SEZcXV/++6+YMPkSXa59EevKSz1ZxmNDd04amswFPqE=
|
||||||
|
github.com/fosrl/newt v0.0.0-20250215225251-76503f3f2cd8/go.mod h1:EeJ6hdGqHhrDJWlZBlNYto7U2yzxjzh1+F5Otyi/2O8=
|
||||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
package logger
|
|
||||||
|
|
||||||
type LogLevel int
|
|
||||||
|
|
||||||
const (
|
|
||||||
DEBUG LogLevel = iota
|
|
||||||
INFO
|
|
||||||
WARN
|
|
||||||
ERROR
|
|
||||||
FATAL
|
|
||||||
)
|
|
||||||
|
|
||||||
var levelStrings = map[LogLevel]string{
|
|
||||||
DEBUG: "DEBUG",
|
|
||||||
INFO: "INFO",
|
|
||||||
WARN: "WARN",
|
|
||||||
ERROR: "ERROR",
|
|
||||||
FATAL: "FATAL",
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the string representation of the log level
|
|
||||||
func (l LogLevel) String() string {
|
|
||||||
if s, ok := levelStrings[l]; ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return "UNKNOWN"
|
|
||||||
}
|
|
||||||
106
logger/logger.go
106
logger/logger.go
@@ -1,106 +0,0 @@
|
|||||||
package logger
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Logger struct holds the logger instance
|
|
||||||
type Logger struct {
|
|
||||||
logger *log.Logger
|
|
||||||
level LogLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
defaultLogger *Logger
|
|
||||||
once sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewLogger creates a new logger instance
|
|
||||||
func NewLogger() *Logger {
|
|
||||||
return &Logger{
|
|
||||||
logger: log.New(os.Stdout, "", 0),
|
|
||||||
level: DEBUG,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init initializes the default logger
|
|
||||||
func Init() *Logger {
|
|
||||||
once.Do(func() {
|
|
||||||
defaultLogger = NewLogger()
|
|
||||||
})
|
|
||||||
return defaultLogger
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLogger returns the default logger instance
|
|
||||||
func GetLogger() *Logger {
|
|
||||||
if defaultLogger == nil {
|
|
||||||
Init()
|
|
||||||
}
|
|
||||||
return defaultLogger
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetLevel sets the minimum logging level
|
|
||||||
func (l *Logger) SetLevel(level LogLevel) {
|
|
||||||
l.level = level
|
|
||||||
}
|
|
||||||
|
|
||||||
// log handles the actual logging
|
|
||||||
func (l *Logger) log(level LogLevel, format string, args ...interface{}) {
|
|
||||||
if level < l.level {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
timestamp := time.Now().Format("2006/01/02 15:04:05")
|
|
||||||
message := fmt.Sprintf(format, args...)
|
|
||||||
l.logger.Printf("%s: %s %s", level.String(), timestamp, message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug logs debug level messages
|
|
||||||
func (l *Logger) Debug(format string, args ...interface{}) {
|
|
||||||
l.log(DEBUG, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Info logs info level messages
|
|
||||||
func (l *Logger) Info(format string, args ...interface{}) {
|
|
||||||
l.log(INFO, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warn logs warning level messages
|
|
||||||
func (l *Logger) Warn(format string, args ...interface{}) {
|
|
||||||
l.log(WARN, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error logs error level messages
|
|
||||||
func (l *Logger) Error(format string, args ...interface{}) {
|
|
||||||
l.log(ERROR, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fatal logs fatal level messages and exits
|
|
||||||
func (l *Logger) Fatal(format string, args ...interface{}) {
|
|
||||||
l.log(FATAL, format, args...)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global helper functions
|
|
||||||
func Debug(format string, args ...interface{}) {
|
|
||||||
GetLogger().Debug(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Info(format string, args ...interface{}) {
|
|
||||||
GetLogger().Info(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Warn(format string, args ...interface{}) {
|
|
||||||
GetLogger().Warn(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Error(format string, args ...interface{}) {
|
|
||||||
GetLogger().Error(format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Fatal(format string, args ...interface{}) {
|
|
||||||
GetLogger().Fatal(format, args...)
|
|
||||||
}
|
|
||||||
4
main.go
4
main.go
@@ -15,8 +15,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fosrl/client/logger"
|
"github.com/fosrl/newt/logger"
|
||||||
"github.com/fosrl/client/websocket"
|
"github.com/fosrl/newt/websocket"
|
||||||
|
|
||||||
"golang.org/x/net/icmp"
|
"golang.org/x/net/icmp"
|
||||||
"golang.org/x/net/ipv4"
|
"golang.org/x/net/ipv4"
|
||||||
|
|||||||
@@ -1,351 +0,0 @@
|
|||||||
package websocket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fosrl/client/logger"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
conn *websocket.Conn
|
|
||||||
config *Config
|
|
||||||
baseURL string
|
|
||||||
handlers map[string]MessageHandler
|
|
||||||
done chan struct{}
|
|
||||||
handlersMux sync.RWMutex
|
|
||||||
|
|
||||||
reconnectInterval time.Duration
|
|
||||||
isConnected bool
|
|
||||||
reconnectMux sync.RWMutex
|
|
||||||
|
|
||||||
onConnect func() error
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientOption func(*Client)
|
|
||||||
|
|
||||||
type MessageHandler func(message WSMessage)
|
|
||||||
|
|
||||||
// WithBaseURL sets the base URL for the client
|
|
||||||
func WithBaseURL(url string) ClientOption {
|
|
||||||
return func(c *Client) {
|
|
||||||
c.baseURL = url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) OnConnect(callback func() error) {
|
|
||||||
c.onConnect = callback
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient creates a new Client client
|
|
||||||
func NewClient(clientID, secret string, endpoint string, opts ...ClientOption) (*Client, error) {
|
|
||||||
config := &Config{
|
|
||||||
ClientID: clientID,
|
|
||||||
Secret: secret,
|
|
||||||
Endpoint: endpoint,
|
|
||||||
}
|
|
||||||
|
|
||||||
client := &Client{
|
|
||||||
config: config,
|
|
||||||
baseURL: endpoint, // default value
|
|
||||||
handlers: make(map[string]MessageHandler),
|
|
||||||
done: make(chan struct{}),
|
|
||||||
reconnectInterval: 10 * time.Second,
|
|
||||||
isConnected: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply options before loading config
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(client)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load existing config if available
|
|
||||||
if err := client.loadConfig(); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to load config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return client, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect establishes the WebSocket connection
|
|
||||||
func (c *Client) Connect() error {
|
|
||||||
go c.connectWithRetry()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes the WebSocket connection
|
|
||||||
func (c *Client) Close() error {
|
|
||||||
close(c.done)
|
|
||||||
if c.conn != nil {
|
|
||||||
return c.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop the ping monitor
|
|
||||||
c.setConnected(false)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendMessage sends a message through the WebSocket connection
|
|
||||||
func (c *Client) SendMessage(messageType string, data interface{}) error {
|
|
||||||
if c.conn == nil {
|
|
||||||
return fmt.Errorf("not connected")
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := WSMessage{
|
|
||||||
Type: messageType,
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.conn.WriteJSON(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterHandler registers a handler for a specific message type
|
|
||||||
func (c *Client) RegisterHandler(messageType string, handler MessageHandler) {
|
|
||||||
c.handlersMux.Lock()
|
|
||||||
defer c.handlersMux.Unlock()
|
|
||||||
c.handlers[messageType] = handler
|
|
||||||
}
|
|
||||||
|
|
||||||
// readPump pumps messages from the WebSocket connection
|
|
||||||
func (c *Client) readPump() {
|
|
||||||
defer c.conn.Close()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-c.done:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
var msg WSMessage
|
|
||||||
err := c.conn.ReadJSON(&msg)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.handlersMux.RLock()
|
|
||||||
if handler, ok := c.handlers[msg.Type]; ok {
|
|
||||||
handler(msg)
|
|
||||||
}
|
|
||||||
c.handlersMux.RUnlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) getToken() (string, error) {
|
|
||||||
// Parse the base URL to ensure we have the correct hostname
|
|
||||||
baseURL, err := url.Parse(c.baseURL)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to parse base URL: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure we have the base URL without trailing slashes
|
|
||||||
baseEndpoint := strings.TrimRight(baseURL.String(), "/")
|
|
||||||
|
|
||||||
// If we already have a token, try to use it
|
|
||||||
if c.config.Token != "" {
|
|
||||||
tokenCheckData := map[string]interface{}{
|
|
||||||
"clientId": c.config.ClientID,
|
|
||||||
"secret": c.config.Secret,
|
|
||||||
"token": c.config.Token,
|
|
||||||
}
|
|
||||||
jsonData, err := json.Marshal(tokenCheckData)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to marshal token check data: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new request
|
|
||||||
req, err := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
baseEndpoint+"/api/v1/auth/client/get-token",
|
|
||||||
bytes.NewBuffer(jsonData),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set headers
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
req.Header.Set("X-CSRF-Token", "x-csrf-protection")
|
|
||||||
|
|
||||||
// Make the request
|
|
||||||
client := &http.Client{}
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to check token validity: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
var tokenResp TokenResponse
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
|
|
||||||
return "", fmt.Errorf("failed to decode token check response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If token is still valid, return it
|
|
||||||
if tokenResp.Success && tokenResp.Message == "Token session already valid" {
|
|
||||||
return c.config.Token, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a new token
|
|
||||||
tokenData := map[string]interface{}{
|
|
||||||
"clientId": c.config.ClientID,
|
|
||||||
"secret": c.config.Secret,
|
|
||||||
}
|
|
||||||
jsonData, err := json.Marshal(tokenData)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to marshal token request data: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new request
|
|
||||||
req, err := http.NewRequest(
|
|
||||||
"POST",
|
|
||||||
baseEndpoint+"/api/v1/auth/client/get-token",
|
|
||||||
bytes.NewBuffer(jsonData),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set headers
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
req.Header.Set("X-CSRF-Token", "x-csrf-protection")
|
|
||||||
|
|
||||||
// Make the request
|
|
||||||
client := &http.Client{}
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to request new token: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
var tokenResp TokenResponse
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
|
|
||||||
return "", fmt.Errorf("failed to decode token response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !tokenResp.Success {
|
|
||||||
return "", fmt.Errorf("failed to get token: %s", tokenResp.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
if tokenResp.Data.Token == "" {
|
|
||||||
return "", fmt.Errorf("received empty token from server")
|
|
||||||
}
|
|
||||||
|
|
||||||
return tokenResp.Data.Token, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) connectWithRetry() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-c.done:
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
err := c.establishConnection()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to connect: %v. Retrying in %v...", err, c.reconnectInterval)
|
|
||||||
time.Sleep(c.reconnectInterval)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) establishConnection() error {
|
|
||||||
// Get token for authentication
|
|
||||||
token, err := c.getToken()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get token: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the base URL to determine protocol and hostname
|
|
||||||
baseURL, err := url.Parse(c.baseURL)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse base URL: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine WebSocket protocol based on HTTP protocol
|
|
||||||
wsProtocol := "wss"
|
|
||||||
if baseURL.Scheme == "http" {
|
|
||||||
wsProtocol = "ws"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create WebSocket URL
|
|
||||||
wsURL := fmt.Sprintf("%s://%s/api/v1/ws", wsProtocol, baseURL.Host)
|
|
||||||
u, err := url.Parse(wsURL)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse WebSocket URL: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add token to query parameters
|
|
||||||
q := u.Query()
|
|
||||||
q.Set("token", token)
|
|
||||||
u.RawQuery = q.Encode()
|
|
||||||
|
|
||||||
// Connect to WebSocket
|
|
||||||
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to connect to WebSocket: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.conn = conn
|
|
||||||
c.setConnected(true)
|
|
||||||
|
|
||||||
// Start the ping monitor
|
|
||||||
go c.pingMonitor()
|
|
||||||
// Start the read pump
|
|
||||||
go c.readPump()
|
|
||||||
|
|
||||||
if c.onConnect != nil {
|
|
||||||
err := c.saveConfig()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to save config: %v", err)
|
|
||||||
}
|
|
||||||
if err := c.onConnect(); err != nil {
|
|
||||||
logger.Error("OnConnect callback failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) pingMonitor() {
|
|
||||||
ticker := time.NewTicker(30 * time.Second)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-c.done:
|
|
||||||
return
|
|
||||||
case <-ticker.C:
|
|
||||||
if err := c.conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(10*time.Second)); err != nil {
|
|
||||||
logger.Error("Ping failed: %v", err)
|
|
||||||
c.reconnect()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) reconnect() {
|
|
||||||
c.setConnected(false)
|
|
||||||
if c.conn != nil {
|
|
||||||
c.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
go c.connectWithRetry()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) setConnected(status bool) {
|
|
||||||
c.reconnectMux.Lock()
|
|
||||||
defer c.reconnectMux.Unlock()
|
|
||||||
c.isConnected = status
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package websocket
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getConfigPath() string {
|
|
||||||
var configDir string
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "darwin":
|
|
||||||
configDir = filepath.Join(os.Getenv("HOME"), "Library", "Application Support", "client-client")
|
|
||||||
case "windows":
|
|
||||||
configDir = filepath.Join(os.Getenv("APPDATA"), "client-client")
|
|
||||||
default: // linux and others
|
|
||||||
configDir = filepath.Join(os.Getenv("HOME"), ".config", "client-client")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
|
||||||
log.Printf("Failed to create config directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.Join(configDir, "config.json")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) loadConfig() error {
|
|
||||||
if c.config.ClientID != "" && c.config.Secret != "" && c.config.Endpoint != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
configPath := getConfigPath()
|
|
||||||
data, err := os.ReadFile(configPath)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var config Config
|
|
||||||
if err := json.Unmarshal(data, &config); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.config.ClientID == "" {
|
|
||||||
c.config.ClientID = config.ClientID
|
|
||||||
}
|
|
||||||
if c.config.Token == "" {
|
|
||||||
c.config.Token = config.Token
|
|
||||||
}
|
|
||||||
if c.config.Secret == "" {
|
|
||||||
c.config.Secret = config.Secret
|
|
||||||
}
|
|
||||||
if c.config.Endpoint == "" {
|
|
||||||
c.config.Endpoint = config.Endpoint
|
|
||||||
c.baseURL = config.Endpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) saveConfig() error {
|
|
||||||
configPath := getConfigPath()
|
|
||||||
data, err := json.MarshalIndent(c.config, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.WriteFile(configPath, data, 0644)
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
package websocket
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
ClientID string `json:"clientId"`
|
|
||||||
Secret string `json:"secret"`
|
|
||||||
Token string `json:"token"`
|
|
||||||
Endpoint string `json:"endpoint"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TokenResponse struct {
|
|
||||||
Data struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
} `json:"data"`
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WSMessage struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Data interface{} `json:"data"`
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user