diff --git a/controllers/hosts.go b/controllers/hosts.go index a9380d22..5bc6fc77 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -28,6 +28,7 @@ func hostHandlers(r *mux.Router) { r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(deleteHostRelay))).Methods(http.MethodDelete) r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost) r.HandleFunc("/api/v1/host", authorize(true, false, "host", http.HandlerFunc(pull))).Methods(http.MethodGet) + r.HandleFunc("/api/hosts/{hostid}/signalpeer", logic.SecurityCheck(false, http.HandlerFunc(createHostRelay))).Methods(http.MethodPost) } // swagger:route GET /api/hosts hosts getHosts @@ -445,3 +446,68 @@ func authenticateHost(response http.ResponseWriter, request *http.Request) { response.Header().Set("Content-Type", "application/json") response.Write(successJSONResponse) } + +// swagger:route POST /api/hosts/{hostid}/signalpeer signalPeer +// +// send signal to peer. +// +// Schemes: https +// +// Security: +// oauth +// +// Responses: +// 200: nodeResponse +func signalPeer(w http.ResponseWriter, r *http.Request) { + var params = mux.Vars(r) + hostid := params["hostid"] + // confirm host exists + currHost, err := logic.GetHost(hostid) + if err != nil { + logger.Log(0, r.Header.Get("user"), "failed to get host:", currHost.ID.String(), err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + var signal models.Signal + w.Header().Set("Content-Type", "application/json") + err = json.NewDecoder(r.Body).Decode(&signal) + if err != nil { + logger.Log(0, r.Header.Get("user"), "error decoding request body: ", err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } + if signal.ToHostPubKey == "" || signal.TurnRelayEndpoint == nil { + msg := "insufficient data to signal peer" + logger.Log(0, r.Header.Get("user"), msg) + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New(msg), "badrequest")) + return + } + hosts, err := logic.GetAllHosts() + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + // push the signal to host through mq + found := false + for _, hostI := range hosts { + if hostI.PublicKey.String() == signal.ToHostPubKey { + // found host publish message and break + found = true + err = mq.HostUpdate(&models.HostUpdate{ + Action: models.SignalHost, + Host: hostI, + Signal: signal, + }) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to publish signal to peer: "+err.Error()), "badrequest")) + return + } + } + } + if !found { + logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to signal, peer not found"), "badrequest")) + return + } + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(signal) +} diff --git a/models/host.go b/models/host.go index 6495d512..eb73cff2 100644 --- a/models/host.go +++ b/models/host.go @@ -102,6 +102,8 @@ func ParseBool(s string) bool { type HostMqAction string const ( + // SignalHost - const for host signal action + SignalHost = "SIGNAL_HOST" // UpdateHost - constant for host update action UpdateHost = "UPDATE_HOST" // DeleteHost - constant for host delete action @@ -121,9 +123,18 @@ type HostUpdate struct { Action HostMqAction Host Host Node Node + Signal Signal } +// HostTurnRegister - struct for host turn registration type HostTurnRegister struct { HostID string `json:"host_id"` HostPassHash string `json:"host_pass_hash"` } + +// Signal - struct for signalling peer +type Signal struct { + FromHostPubKey string `json:"from_host_pubkey"` + TurnRelayEndpoint *net.PacketConn `json:"turn_relay_addr"` + ToHostPubKey string `json:"to_host_pubkey"` +}