mirror of
https://github.com/0x1d/rcond.git
synced 2025-12-14 18:25:21 +01:00
feat: refactoring
This commit is contained in:
@@ -10,16 +10,18 @@ import (
|
|||||||
"github.com/hashicorp/serf/serf"
|
"github.com/hashicorp/serf/serf"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Agent represents a Serf cluster agent.
|
||||||
type Agent struct {
|
type Agent struct {
|
||||||
Serf *serf.Serf
|
Serf *serf.Serf
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterEvent represents a custom event that will be sent to the Serf cluster
|
// ClusterEvent represents a custom event that will be sent to the Serf cluster.
|
||||||
type ClusterEvent struct {
|
type ClusterEvent struct {
|
||||||
Name string
|
Name string
|
||||||
Data []byte
|
Data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAgent creates a new Serf cluster agent with the given configuration and event handlers.
|
||||||
func NewAgent(clusterConfig *config.ClusterConfig, clusterEvents map[string]func([]byte)) (*Agent, error) {
|
func NewAgent(clusterConfig *config.ClusterConfig, clusterEvents map[string]func([]byte)) (*Agent, error) {
|
||||||
config := serf.DefaultConfig()
|
config := serf.DefaultConfig()
|
||||||
config.Init()
|
config.Init()
|
||||||
@@ -65,11 +67,13 @@ func (a *Agent) Event(event ClusterEvent) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Members returns a list of members in the Serf cluster.
|
||||||
func (a *Agent) Members() ([]serf.Member, error) {
|
func (a *Agent) Members() ([]serf.Member, error) {
|
||||||
log.Printf("Getting members of the cluster")
|
log.Printf("Getting members of the cluster")
|
||||||
return a.Serf.Members(), nil
|
return a.Serf.Members(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Join attempts to join the Serf cluster with the given addresses, optionally ignoring old nodes.
|
||||||
func (a *Agent) Join(addrs []string, ignoreOld bool) (int, error) {
|
func (a *Agent) Join(addrs []string, ignoreOld bool) (int, error) {
|
||||||
log.Printf("Joining nodes in the cluster: %v", addrs)
|
log.Printf("Joining nodes in the cluster: %v", addrs)
|
||||||
n, err := a.Serf.Join(addrs, ignoreOld)
|
n, err := a.Serf.Join(addrs, ignoreOld)
|
||||||
@@ -81,16 +85,18 @@ func (a *Agent) Join(addrs []string, ignoreOld bool) (int, error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Leave causes the agent to leave the Serf cluster.
|
||||||
func (a *Agent) Leave() error {
|
func (a *Agent) Leave() error {
|
||||||
return a.Serf.Leave()
|
return a.Serf.Leave()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown shuts down the Serf cluster agent.
|
||||||
func (a *Agent) Shutdown() error {
|
func (a *Agent) Shutdown() error {
|
||||||
log.Printf("Shutting down cluster agent")
|
log.Printf("Shutting down cluster agent")
|
||||||
return a.Serf.Shutdown()
|
return a.Serf.Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleEvents handles Serf events received on the event channel
|
// handleEvents handles Serf events received on the event channel.
|
||||||
func handleEvents(eventCh chan serf.Event, clusterEvents map[string]func([]byte)) {
|
func handleEvents(eventCh chan serf.Event, clusterEvents map[string]func([]byte)) {
|
||||||
for event := range eventCh {
|
for event := range eventCh {
|
||||||
switch event.EventType() {
|
switch event.EventType() {
|
||||||
|
|||||||
96
pkg/http/handle_cluster.go
Normal file
96
pkg/http/handle_cluster.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/0x1d/rcond/pkg/cluster"
|
||||||
|
)
|
||||||
|
|
||||||
|
type clusterEventRequest struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Payload string `json:"payload,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClusterAgentHandler(agent *cluster.Agent, handler func(http.ResponseWriter, *http.Request, *cluster.Agent)) func(http.ResponseWriter, *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handler(w, r, agent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleClusterJoin(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
||||||
|
var joinRequest struct {
|
||||||
|
Join []string `json:"join"`
|
||||||
|
}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&joinRequest)
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, "Invalid request body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
joinAddrs := strings.Join(joinRequest.Join, ",")
|
||||||
|
if joinAddrs == "" {
|
||||||
|
WriteError(w, "No join addresses provided", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs := strings.Split(joinAddrs, ",")
|
||||||
|
n, err := agent.Join(addrs, true)
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]int{"joined": n})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleClusterLeave(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
||||||
|
err := agent.Leave()
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleClusterMembers(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
||||||
|
if agent == nil {
|
||||||
|
WriteError(w, "cluster agent is not initialized", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
members, err := agent.Members()
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(members)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleClusterEvent(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
||||||
|
if agent == nil {
|
||||||
|
WriteError(w, "cluster agent is not initialized", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req clusterEventRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
event := cluster.ClusterEvent{
|
||||||
|
Name: req.Name,
|
||||||
|
Data: []byte(req.Payload),
|
||||||
|
}
|
||||||
|
err := agent.Event(event)
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
16
pkg/http/handle_error.go
Normal file
16
pkg/http/handle_error.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteError(w http.ResponseWriter, message string, code int) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(code)
|
||||||
|
json.NewEncoder(w).Encode(ErrorResponse{Error: message})
|
||||||
|
}
|
||||||
153
pkg/http/handle_network.go
Normal file
153
pkg/http/handle_network.go
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
network "github.com/0x1d/rcond/pkg/network"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
type configureAPRequest struct {
|
||||||
|
Interface string `json:"interface"`
|
||||||
|
SSID string `json:"ssid"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Autoconnect bool `json:"autoconnect"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type configureSTARequest struct {
|
||||||
|
Interface string `json:"interface"`
|
||||||
|
SSID string `json:"ssid"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Autoconnect bool `json:"autoconnect"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type networkUpRequest struct {
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type setHostnameRequest struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleConfigureSTA(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req configureSTARequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Configuring station on interface %s", req.Interface)
|
||||||
|
uuid, err := network.ConfigureSTA(req.Interface, req.SSID, req.Password, req.Autoconnect)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to configure station on interface %s: %v", req.Interface, err)
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"uuid": uuid})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleConfigureAP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req configureAPRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Configuring access point on interface %s", req.Interface)
|
||||||
|
uuid, err := network.ConfigureAP(req.Interface, req.SSID, req.Password, req.Autoconnect)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to configure access point on interface %s: %v", req.Interface, err)
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Successfully configured access point on interface %s with UUID %s", req.Interface, uuid)
|
||||||
|
|
||||||
|
resp := struct {
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
}{
|
||||||
|
UUID: uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||||
|
log.Printf("Failed to encode response: %v", err)
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleNetworkUp(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req networkUpRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
iface := vars["interface"]
|
||||||
|
|
||||||
|
log.Printf("Bringing up network interface %s with UUID %s", iface, req.UUID)
|
||||||
|
if err := network.Up(iface, req.UUID); err != nil {
|
||||||
|
log.Printf("Failed to bring up network interface %s: %v", iface, err)
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Successfully brought up network interface %s", iface)
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleNetworkDown(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
iface := vars["interface"]
|
||||||
|
if err := network.Down(iface); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleNetworkRemove(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
uuid := vars["uuid"]
|
||||||
|
if err := network.Remove(uuid); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleGetHostname(w http.ResponseWriter, r *http.Request) {
|
||||||
|
hostname, err := network.GetHostname()
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"hostname": hostname})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleSetHostname(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req setHostnameRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := network.SetHostname(req.Hostname); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
28
pkg/http/handle_system.go
Normal file
28
pkg/http/handle_system.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/0x1d/rcond/pkg/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HandleReboot(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err := system.Restart(); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleShutdown(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err := system.Shutdown(); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
63
pkg/http/handle_user.go
Normal file
63
pkg/http/handle_user.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/0x1d/rcond/pkg/user"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
type authorizedKeyRequest struct {
|
||||||
|
User string `json:"user"`
|
||||||
|
PubKey string `json:"pubkey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleAddAuthorizedKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var req authorizedKeyRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
username := vars["user"]
|
||||||
|
|
||||||
|
fingerprint, err := user.AddAuthorizedKey(username, req.PubKey)
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"fingerprint": fingerprint})
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleRemoveAuthorizedKey(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
fingerprint := vars["fingerprint"]
|
||||||
|
if fingerprint == "" {
|
||||||
|
WriteError(w, "fingerprint parameter is required", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
username := vars["user"]
|
||||||
|
if username == "" {
|
||||||
|
WriteError(w, "user parameter is required", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fingerprintBytes, err := base64.RawURLEncoding.DecodeString(fingerprint)
|
||||||
|
if err != nil {
|
||||||
|
WriteError(w, "invalid fingerprint base64", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := user.RemoveAuthorizedKey(username, string(fingerprintBytes)); err != nil {
|
||||||
|
WriteError(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
||||||
|
}
|
||||||
@@ -1,328 +0,0 @@
|
|||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/0x1d/rcond/pkg/cluster"
|
|
||||||
network "github.com/0x1d/rcond/pkg/network"
|
|
||||||
"github.com/0x1d/rcond/pkg/system"
|
|
||||||
"github.com/0x1d/rcond/pkg/user"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
|
||||||
|
|
||||||
type configureAPRequest struct {
|
|
||||||
Interface string `json:"interface"`
|
|
||||||
SSID string `json:"ssid"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
Autoconnect bool `json:"autoconnect"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type configureSTARequest struct {
|
|
||||||
Interface string `json:"interface"`
|
|
||||||
SSID string `json:"ssid"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
Autoconnect bool `json:"autoconnect"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type networkUpRequest struct {
|
|
||||||
UUID string `json:"uuid"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type setHostnameRequest struct {
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type authorizedKeyRequest struct {
|
|
||||||
User string `json:"user"`
|
|
||||||
PubKey string `json:"pubkey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type clusterEventRequest struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Payload string `json:"payload,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type errorResponse struct {
|
|
||||||
Error string `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeError(w http.ResponseWriter, message string, code int) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(code)
|
|
||||||
json.NewEncoder(w).Encode(errorResponse{Error: message})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleConfigureSTA(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req configureSTARequest
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Configuring station on interface %s", req.Interface)
|
|
||||||
uuid, err := network.ConfigureSTA(req.Interface, req.SSID, req.Password, req.Autoconnect)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to configure station on interface %s: %v", req.Interface, err)
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"uuid": uuid})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleConfigureAP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req configureAPRequest
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Configuring access point on interface %s", req.Interface)
|
|
||||||
uuid, err := network.ConfigureAP(req.Interface, req.SSID, req.Password, req.Autoconnect)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to configure access point on interface %s: %v", req.Interface, err)
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("Successfully configured access point on interface %s with UUID %s", req.Interface, uuid)
|
|
||||||
|
|
||||||
resp := struct {
|
|
||||||
UUID string `json:"uuid"`
|
|
||||||
}{
|
|
||||||
UUID: uuid,
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
|
||||||
log.Printf("Failed to encode response: %v", err)
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleNetworkUp(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req networkUpRequest
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
iface := vars["interface"]
|
|
||||||
|
|
||||||
log.Printf("Bringing up network interface %s with UUID %s", iface, req.UUID)
|
|
||||||
if err := network.Up(iface, req.UUID); err != nil {
|
|
||||||
log.Printf("Failed to bring up network interface %s: %v", iface, err)
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("Successfully brought up network interface %s", iface)
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleNetworkDown(w http.ResponseWriter, r *http.Request) {
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
iface := vars["interface"]
|
|
||||||
if err := network.Down(iface); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleNetworkRemove(w http.ResponseWriter, r *http.Request) {
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
uuid := vars["uuid"]
|
|
||||||
if err := network.Remove(uuid); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleGetHostname(w http.ResponseWriter, r *http.Request) {
|
|
||||||
hostname, err := network.GetHostname()
|
|
||||||
if err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"hostname": hostname})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleSetHostname(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req setHostnameRequest
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := network.SetHostname(req.Hostname); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleAddAuthorizedKey(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var req authorizedKeyRequest
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
username := vars["user"]
|
|
||||||
|
|
||||||
fingerprint, err := user.AddAuthorizedKey(username, req.PubKey)
|
|
||||||
if err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"fingerprint": fingerprint})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleRemoveAuthorizedKey(w http.ResponseWriter, r *http.Request) {
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
fingerprint := vars["fingerprint"]
|
|
||||||
if fingerprint == "" {
|
|
||||||
writeError(w, "fingerprint parameter is required", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
username := vars["user"]
|
|
||||||
if username == "" {
|
|
||||||
writeError(w, "user parameter is required", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fingerprintBytes, err := base64.RawURLEncoding.DecodeString(fingerprint)
|
|
||||||
if err != nil {
|
|
||||||
writeError(w, "invalid fingerprint base64", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := user.RemoveAuthorizedKey(username, string(fingerprintBytes)); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleReboot(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if err := system.Restart(); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleShutdown(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if err := system.Shutdown(); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ClusterAgentHandler(agent *cluster.Agent, handler func(http.ResponseWriter, *http.Request, *cluster.Agent)) func(http.ResponseWriter, *http.Request) {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
handler(w, r, agent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleClusterJoin(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
|
||||||
var joinRequest struct {
|
|
||||||
Join []string `json:"join"`
|
|
||||||
}
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&joinRequest)
|
|
||||||
if err != nil {
|
|
||||||
writeError(w, "Invalid request body", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
joinAddrs := strings.Join(joinRequest.Join, ",")
|
|
||||||
if joinAddrs == "" {
|
|
||||||
writeError(w, "No join addresses provided", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
addrs := strings.Split(joinAddrs, ",")
|
|
||||||
n, err := agent.Join(addrs, true)
|
|
||||||
if err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]int{"joined": n})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleClusterLeave(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
|
||||||
err := agent.Leave()
|
|
||||||
if err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleClusterMembers(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
|
||||||
if agent == nil {
|
|
||||||
writeError(w, "cluster agent is not initialized", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
members, err := agent.Members()
|
|
||||||
if err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(members)
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleClusterEvent(w http.ResponseWriter, r *http.Request, agent *cluster.Agent) {
|
|
||||||
if agent == nil {
|
|
||||||
writeError(w, "cluster agent is not initialized", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var req clusterEventRequest
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
event := cluster.ClusterEvent{
|
|
||||||
Name: req.Name,
|
|
||||||
Data: []byte(req.Payload),
|
|
||||||
}
|
|
||||||
err := agent.Event(event)
|
|
||||||
if err != nil {
|
|
||||||
writeError(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(map[string]string{"status": "success"})
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user