telebit/client/client.go

73 lines
1.9 KiB
Go

package client
import (
"context"
"crypto/tls"
"fmt"
"net/url"
"time"
"github.com/gorilla/websocket"
)
// The Config struct holds all of the information needed to establish and handle a connection
// with the RVPN server.
type Config struct {
Server string
Token string
Insecure bool
Services map[string]map[string]int
}
// Run establishes a connection with the RVPN server specified in the config. If the first attempt
// to connect fails it is assumed that something is wrong with the authentication and it will
// return an error. Otherwise it will continuously attempt to reconnect whenever the connection
// is broken.
func Run(ctx context.Context, config *Config) error {
serverURL, err := url.Parse(config.Server)
if err != nil {
return fmt.Errorf("Invalid server URL: %v", err)
}
if serverURL.Scheme == "" {
serverURL.Scheme = "wss"
}
serverURL.Path = ""
query := make(url.Values)
query.Set("access_token", config.Token)
serverURL.RawQuery = query.Encode()
dialer := websocket.Dialer{}
if config.Insecure {
dialer.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
for name, portList := range config.Services {
if _, ok := portList["*"]; !ok {
return fmt.Errorf(`service %s missing port for "*"`, name)
}
}
handler := NewWsHandler(config.Services)
authenticated := false
for {
fmt.Printf("debug serverURL:\n%+v", serverURL)
if conn, _, err := dialer.Dial(serverURL.String(), nil); err == nil {
loginfo.Println("connected to remote server")
authenticated = true
handler.HandleConn(ctx, conn)
} else if !authenticated {
return fmt.Errorf("first connection to server failed - check auth: %s", err.Error())
}
loginfo.Println("disconnected from remote server")
// Sleep for a few seconds before trying again, but only if the context is still active
select {
case <-ctx.Done():
return nil
case <-time.After(5 * time.Second):
}
loginfo.Println("attempting reconnect to remote server")
}
}