Code refactoring for HomeKit server
This commit is contained in:
+67
-38
@@ -3,6 +3,7 @@ package homekit
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@@ -14,56 +15,84 @@ import (
|
||||
"github.com/AlexxIT/go2rtc/pkg/mdns"
|
||||
)
|
||||
|
||||
func apiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func apiDiscovery(w http.ResponseWriter, r *http.Request) {
|
||||
sources, err := discovery()
|
||||
if err != nil {
|
||||
api.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
urls := findHomeKitURLs()
|
||||
for id, u := range urls {
|
||||
deviceID := u.Query().Get("device_id")
|
||||
for _, source := range sources {
|
||||
if strings.Contains(source.URL, deviceID) {
|
||||
source.Location = id
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
if source.Location == "" {
|
||||
source.Location = " "
|
||||
}
|
||||
}
|
||||
|
||||
api.ResponseSources(w, sources)
|
||||
}
|
||||
|
||||
func apiHomekit(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case "GET":
|
||||
sources, err := discovery()
|
||||
if err != nil {
|
||||
api.Error(w, err)
|
||||
return
|
||||
if id := r.Form.Get("id"); id != "" {
|
||||
api.ResponsePrettyJSON(w, servers[id])
|
||||
} else {
|
||||
api.ResponsePrettyJSON(w, servers)
|
||||
}
|
||||
|
||||
urls := findHomeKitURLs()
|
||||
for id, u := range urls {
|
||||
deviceID := u.Query().Get("device_id")
|
||||
for _, source := range sources {
|
||||
if strings.Contains(source.URL, deviceID) {
|
||||
source.Location = id
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, source := range sources {
|
||||
if source.Location == "" {
|
||||
source.Location = " "
|
||||
}
|
||||
}
|
||||
|
||||
api.ResponseSources(w, sources)
|
||||
|
||||
case "POST":
|
||||
if err := r.ParseMultipartForm(1024); err != nil {
|
||||
api.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := apiPair(r.Form.Get("id"), r.Form.Get("url")); err != nil {
|
||||
api.Error(w, err)
|
||||
id := r.Form.Get("id")
|
||||
rawURL := r.Form.Get("src") + "&pin=" + r.Form.Get("pin")
|
||||
if err := apiPair(id, rawURL); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
case "DELETE":
|
||||
if err := r.ParseMultipartForm(1024); err != nil {
|
||||
api.Error(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := apiUnpair(r.Form.Get("id")); err != nil {
|
||||
api.Error(w, err)
|
||||
id := r.Form.Get("id")
|
||||
if err := apiUnpair(id); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func apiHomekitAccessories(w http.ResponseWriter, r *http.Request) {
|
||||
src := r.URL.Query().Get("src")
|
||||
stream := streams.Get(src)
|
||||
rawURL := findHomeKitURL(stream.Sources())
|
||||
|
||||
client, err := hap.Dial(rawURL)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
res, err := client.Get(hap.PathAccessories)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", api.MimeJSON)
|
||||
_, _ = io.Copy(w, res.Body)
|
||||
}
|
||||
|
||||
func discovery() ([]*api.Source, error) {
|
||||
var sources []*api.Source
|
||||
|
||||
|
||||
+25
-51
@@ -2,8 +2,6 @@ package homekit
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@@ -35,12 +33,15 @@ func Init() {
|
||||
|
||||
streams.HandleFunc("homekit", streamHandler)
|
||||
|
||||
api.HandleFunc("api/homekit", apiHandler)
|
||||
api.HandleFunc("api/homekit", apiHomekit)
|
||||
api.HandleFunc("api/homekit/accessories", apiHomekitAccessories)
|
||||
api.HandleFunc("api/discovery/homekit", apiDiscovery)
|
||||
|
||||
if cfg.Mod == nil {
|
||||
return
|
||||
}
|
||||
|
||||
hosts = map[string]*server{}
|
||||
servers = map[string]*server{}
|
||||
var entries []*mdns.ServiceEntry
|
||||
|
||||
@@ -66,33 +67,14 @@ func Init() {
|
||||
|
||||
srv := &server{
|
||||
stream: id,
|
||||
srtp: srtp.Server,
|
||||
pairings: conf.Pairings,
|
||||
}
|
||||
|
||||
srv.hap = &hap.Server{
|
||||
Pin: pin,
|
||||
DeviceID: deviceID,
|
||||
DevicePrivate: calcDevicePrivate(conf.DevicePrivate, id),
|
||||
GetPair: srv.GetPair,
|
||||
AddPair: srv.AddPair,
|
||||
Handler: homekit.ServerHandler(srv),
|
||||
}
|
||||
|
||||
if url := findHomeKitURL(stream.Sources()); url != "" {
|
||||
// 1. Act as transparent proxy for HomeKit camera
|
||||
dial := func() (net.Conn, error) {
|
||||
client, err := homekit.Dial(url, srtp.Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client.Conn(), nil
|
||||
}
|
||||
srv.hap.Handler = homekit.ProxyHandler(srv, dial)
|
||||
} else {
|
||||
// 2. Act as basic HomeKit camera
|
||||
srv.accessory = camera.NewAccessory("AlexxIT", "go2rtc", name, "-", app.Version)
|
||||
srv.hap.Handler = homekit.ServerHandler(srv)
|
||||
Pin: pin,
|
||||
DeviceID: deviceID,
|
||||
DevicePrivate: calcDevicePrivate(conf.DevicePrivate, id),
|
||||
GetClientPublic: srv.GetPair,
|
||||
}
|
||||
|
||||
srv.mdns = &mdns.ServiceEntry{
|
||||
@@ -114,15 +96,24 @@ func Init() {
|
||||
|
||||
srv.UpdateStatus()
|
||||
|
||||
if url := findHomeKitURL(stream.Sources()); url != "" {
|
||||
// 1. Act as transparent proxy for HomeKit camera
|
||||
srv.proxyURL = url
|
||||
} else {
|
||||
// 2. Act as basic HomeKit camera
|
||||
srv.accessory = camera.NewAccessory("AlexxIT", "go2rtc", name, "-", app.Version)
|
||||
}
|
||||
|
||||
host := srv.mdns.Host(mdns.ServiceHAP)
|
||||
servers[host] = srv
|
||||
hosts[host] = srv
|
||||
servers[id] = srv
|
||||
|
||||
log.Trace().Msgf("[homekit] new server: %s", srv.mdns)
|
||||
}
|
||||
|
||||
api.HandleFunc(hap.PathPairSetup, hapHandler)
|
||||
api.HandleFunc(hap.PathPairVerify, hapHandler)
|
||||
|
||||
log.Trace().Msgf("[homekit] mdns: %s", entries)
|
||||
|
||||
go func() {
|
||||
if err := mdns.Serve(mdns.ServiceHAP, entries); err != nil {
|
||||
log.Error().Err(err).Caller().Send()
|
||||
@@ -131,6 +122,7 @@ func Init() {
|
||||
}
|
||||
|
||||
var log zerolog.Logger
|
||||
var hosts map[string]*server
|
||||
var servers map[string]*server
|
||||
|
||||
func streamHandler(rawURL string) (core.Producer, error) {
|
||||
@@ -149,45 +141,27 @@ func streamHandler(rawURL string) (core.Producer, error) {
|
||||
}
|
||||
|
||||
func resolve(host string) *server {
|
||||
if len(servers) == 1 {
|
||||
for _, srv := range servers {
|
||||
if len(hosts) == 1 {
|
||||
for _, srv := range hosts {
|
||||
return srv
|
||||
}
|
||||
}
|
||||
if srv, ok := servers[host]; ok {
|
||||
if srv, ok := hosts[host]; ok {
|
||||
return srv
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func hapHandler(w http.ResponseWriter, r *http.Request) {
|
||||
conn, rw, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
// Can support multiple HomeKit cameras on single port ONLY for Apple devices.
|
||||
// Doesn't support Home Assistant and any other open source projects
|
||||
// because they don't send the host header in requests.
|
||||
srv := resolve(r.Host)
|
||||
if srv == nil {
|
||||
log.Error().Msg("[homekit] unknown host: " + r.Host)
|
||||
_ = hap.WriteBackoff(rw)
|
||||
return
|
||||
}
|
||||
|
||||
switch r.RequestURI {
|
||||
case hap.PathPairSetup:
|
||||
err = srv.hap.PairSetup(r, rw, conn)
|
||||
case hap.PathPairVerify:
|
||||
err = srv.hap.PairVerify(r, rw, conn)
|
||||
}
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
log.Error().Err(err).Caller().Send()
|
||||
}
|
||||
srv.Handle(w, r)
|
||||
}
|
||||
|
||||
func findHomeKitURL(sources []string) string {
|
||||
|
||||
+206
-93
@@ -4,10 +4,16 @@ import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/internal/app"
|
||||
"github.com/AlexxIT/go2rtc/internal/ffmpeg"
|
||||
@@ -16,23 +22,133 @@ import (
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap"
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap/camera"
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap/hds"
|
||||
"github.com/AlexxIT/go2rtc/pkg/hap/tlv8"
|
||||
"github.com/AlexxIT/go2rtc/pkg/homekit"
|
||||
"github.com/AlexxIT/go2rtc/pkg/magic"
|
||||
"github.com/AlexxIT/go2rtc/pkg/mdns"
|
||||
"github.com/AlexxIT/go2rtc/pkg/srtp"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
stream string // stream name from YAML
|
||||
hap *hap.Server // server for HAP connection and encryption
|
||||
mdns *mdns.ServiceEntry
|
||||
srtp *srtp.Server
|
||||
accessory *hap.Accessory // HAP accessory
|
||||
pairings []string // pairings list
|
||||
hap *hap.Server // server for HAP connection and encryption
|
||||
mdns *mdns.ServiceEntry
|
||||
|
||||
streams map[string]*homekit.Consumer
|
||||
consumer *homekit.Consumer
|
||||
pairings []string // pairings list
|
||||
conns []any
|
||||
mu sync.Mutex
|
||||
|
||||
accessory *hap.Accessory // HAP accessory
|
||||
consumer *homekit.Consumer
|
||||
proxyURL string
|
||||
stream string // stream name from YAML
|
||||
}
|
||||
|
||||
func (s *server) MarshalJSON() ([]byte, error) {
|
||||
v := struct {
|
||||
Name string `json:"name"`
|
||||
DeviceID string `json:"device_id"`
|
||||
Paired int `json:"paired"`
|
||||
Conns []any `json:"connections"`
|
||||
}{
|
||||
Name: s.mdns.Name,
|
||||
DeviceID: s.mdns.Info[hap.TXTDeviceID],
|
||||
Paired: len(s.pairings),
|
||||
Conns: s.conns,
|
||||
}
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (s *server) Handle(w http.ResponseWriter, r *http.Request) {
|
||||
conn, rw, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
// Fix reading from Body after Hijack.
|
||||
r.Body = io.NopCloser(rw)
|
||||
|
||||
switch r.RequestURI {
|
||||
case hap.PathPairSetup:
|
||||
id, key, err := s.hap.PairSetup(r, rw)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Caller().Send()
|
||||
return
|
||||
}
|
||||
|
||||
s.AddPair(id, key, hap.PermissionAdmin)
|
||||
|
||||
case hap.PathPairVerify:
|
||||
id, key, err := s.hap.PairVerify(r, rw)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Caller().Send()
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug().Str("stream", s.stream).Str("client_id", id).Msgf("[homekit] %s: new conn", conn.RemoteAddr())
|
||||
|
||||
controller, err := hap.NewConn(conn, rw, key, false)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Caller().Send()
|
||||
return
|
||||
}
|
||||
|
||||
s.AddConn(controller)
|
||||
defer s.DelConn(controller)
|
||||
|
||||
var handler homekit.HandlerFunc
|
||||
|
||||
switch {
|
||||
case s.accessory != nil:
|
||||
handler = homekit.ServerHandler(s)
|
||||
case s.proxyURL != "":
|
||||
client, err := hap.Dial(s.proxyURL)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Caller().Send()
|
||||
return
|
||||
}
|
||||
handler = homekit.ProxyHandler(s, client.Conn)
|
||||
}
|
||||
|
||||
// If your iPhone goes to sleep, it will be an EOF error.
|
||||
if err = handler(controller); err != nil && !errors.Is(err, io.EOF) {
|
||||
log.Error().Err(err).Caller().Send()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type logger struct {
|
||||
v any
|
||||
}
|
||||
|
||||
func (l logger) String() string {
|
||||
switch v := l.v.(type) {
|
||||
case *hap.Conn:
|
||||
return "hap " + v.RemoteAddr().String()
|
||||
case *hds.Conn:
|
||||
return "hds " + v.RemoteAddr().String()
|
||||
case *homekit.Consumer:
|
||||
return "rtp " + v.RemoteAddr
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func (s *server) AddConn(v any) {
|
||||
log.Trace().Str("stream", s.stream).Msgf("[homekit] add conn %s", logger{v})
|
||||
s.mu.Lock()
|
||||
s.conns = append(s.conns, v)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *server) DelConn(v any) {
|
||||
log.Trace().Str("stream", s.stream).Msgf("[homekit] del conn %s", logger{v})
|
||||
s.mu.Lock()
|
||||
if i := slices.Index(s.conns, v); i >= 0 {
|
||||
s.conns = slices.Delete(s.conns, i, i+1)
|
||||
}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *server) UpdateStatus() {
|
||||
@@ -44,12 +160,68 @@ func (s *server) UpdateStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) pairIndex(id string) int {
|
||||
id = "client_id=" + id
|
||||
for i, pairing := range s.pairings {
|
||||
if strings.HasPrefix(pairing, id) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func (s *server) GetPair(id string) []byte {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if i := s.pairIndex(id); i >= 0 {
|
||||
query, _ := url.ParseQuery(s.pairings[i])
|
||||
b, _ := hex.DecodeString(query.Get("client_public"))
|
||||
return b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) AddPair(id string, public []byte, permissions byte) {
|
||||
log.Debug().Str("stream", s.stream).Msgf("[homekit] add pair id=%s public=%x perm=%d", id, public, permissions)
|
||||
|
||||
s.mu.Lock()
|
||||
if s.pairIndex(id) < 0 {
|
||||
s.pairings = append(s.pairings, fmt.Sprintf(
|
||||
"client_id=%s&client_public=%x&permissions=%d", id, public, permissions,
|
||||
))
|
||||
s.UpdateStatus()
|
||||
s.PatchConfig()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *server) DelPair(id string) {
|
||||
log.Debug().Str("stream", s.stream).Msgf("[homekit] del pair id=%s", id)
|
||||
|
||||
s.mu.Lock()
|
||||
if i := s.pairIndex(id); i >= 0 {
|
||||
s.pairings = append(s.pairings[:i], s.pairings[i+1:]...)
|
||||
s.UpdateStatus()
|
||||
s.PatchConfig()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *server) PatchConfig() {
|
||||
if err := app.PatchConfig([]string{"homekit", s.stream, "pairings"}, s.pairings); err != nil {
|
||||
log.Error().Err(err).Msgf(
|
||||
"[homekit] can't save %s pairings=%v", s.stream, s.pairings,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) GetAccessories(_ net.Conn) []*hap.Accessory {
|
||||
return []*hap.Accessory{s.accessory}
|
||||
}
|
||||
|
||||
func (s *server) GetCharacteristic(conn net.Conn, aid uint8, iid uint64) any {
|
||||
log.Trace().Msgf("[homekit] %s: get char aid=%d iid=0x%x", conn.RemoteAddr(), aid, iid)
|
||||
log.Trace().Str("stream", s.stream).Msgf("[homekit] get char aid=%d iid=0x%x", aid, iid)
|
||||
|
||||
char := s.accessory.GetCharacterByID(iid)
|
||||
if char == nil {
|
||||
@@ -59,11 +231,12 @@ func (s *server) GetCharacteristic(conn net.Conn, aid uint8, iid uint64) any {
|
||||
|
||||
switch char.Type {
|
||||
case camera.TypeSetupEndpoints:
|
||||
if s.consumer == nil {
|
||||
consumer := s.consumer
|
||||
if consumer == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
answer := s.consumer.GetAnswer()
|
||||
answer := consumer.GetAnswer()
|
||||
v, err := tlv8.MarshalBase64(answer)
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -76,7 +249,7 @@ func (s *server) GetCharacteristic(conn net.Conn, aid uint8, iid uint64) any {
|
||||
}
|
||||
|
||||
func (s *server) SetCharacteristic(conn net.Conn, aid uint8, iid uint64, value any) {
|
||||
log.Trace().Msgf("[homekit] %s: set char aid=%d iid=0x%x value=%v", conn.RemoteAddr(), aid, iid, value)
|
||||
log.Trace().Str("stream", s.stream).Msgf("[homekit] set char aid=%d iid=0x%x value=%v", aid, iid, value)
|
||||
|
||||
char := s.accessory.GetCharacterByID(iid)
|
||||
if char == nil {
|
||||
@@ -91,8 +264,9 @@ func (s *server) SetCharacteristic(conn net.Conn, aid uint8, iid uint64, value a
|
||||
return
|
||||
}
|
||||
|
||||
s.consumer = homekit.NewConsumer(conn, srtp2.Server)
|
||||
s.consumer.SetOffer(&offer)
|
||||
consumer := homekit.NewConsumer(conn, srtp2.Server)
|
||||
consumer.SetOffer(&offer)
|
||||
s.consumer = consumer
|
||||
|
||||
case camera.TypeSelectedStreamConfiguration:
|
||||
var conf camera.SelectedStreamConfiguration
|
||||
@@ -100,47 +274,49 @@ func (s *server) SetCharacteristic(conn net.Conn, aid uint8, iid uint64, value a
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace().Msgf("[homekit] %s stream id=%x cmd=%d", conn.RemoteAddr(), conf.Control.SessionID, conf.Control.Command)
|
||||
log.Trace().Str("stream", s.stream).Msgf("[homekit] stream id=%x cmd=%d", conf.Control.SessionID, conf.Control.Command)
|
||||
|
||||
switch conf.Control.Command {
|
||||
case camera.SessionCommandEnd:
|
||||
if consumer := s.streams[conf.Control.SessionID]; consumer != nil {
|
||||
_ = consumer.Stop()
|
||||
for _, consumer := range s.conns {
|
||||
if consumer, ok := consumer.(*homekit.Consumer); ok {
|
||||
if consumer.SessionID() == conf.Control.SessionID {
|
||||
_ = consumer.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case camera.SessionCommandStart:
|
||||
if s.consumer == nil {
|
||||
consumer := s.consumer
|
||||
if consumer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !s.consumer.SetConfig(&conf) {
|
||||
if !consumer.SetConfig(&conf) {
|
||||
log.Warn().Msgf("[homekit] wrong config")
|
||||
return
|
||||
}
|
||||
|
||||
if s.streams == nil {
|
||||
s.streams = map[string]*homekit.Consumer{}
|
||||
}
|
||||
|
||||
s.streams[conf.Control.SessionID] = s.consumer
|
||||
s.AddConn(consumer)
|
||||
|
||||
stream := streams.Get(s.stream)
|
||||
if err := stream.AddConsumer(s.consumer); err != nil {
|
||||
if err := stream.AddConsumer(consumer); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
_, _ = s.consumer.WriteTo(nil)
|
||||
stream.RemoveConsumer(s.consumer)
|
||||
_, _ = consumer.WriteTo(nil)
|
||||
stream.RemoveConsumer(consumer)
|
||||
|
||||
delete(s.streams, conf.Control.SessionID)
|
||||
s.DelConn(consumer)
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) GetImage(conn net.Conn, width, height int) []byte {
|
||||
log.Trace().Msgf("[homekit] %s: get image width=%d height=%d", conn.RemoteAddr(), width, height)
|
||||
log.Trace().Str("stream", s.stream).Msgf("[homekit] get image width=%d height=%d", width, height)
|
||||
|
||||
stream := streams.Get(s.stream)
|
||||
cons := magic.NewKeyframe()
|
||||
@@ -166,69 +342,6 @@ func (s *server) GetImage(conn net.Conn, width, height int) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
func (s *server) GetPair(conn net.Conn, id string) []byte {
|
||||
log.Trace().Msgf("[homekit] %s: get pair id=%s", conn.RemoteAddr(), id)
|
||||
|
||||
for _, pairing := range s.pairings {
|
||||
if !strings.Contains(pairing, id) {
|
||||
continue
|
||||
}
|
||||
|
||||
query, err := url.ParseQuery(pairing)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if query.Get("client_id") != id {
|
||||
continue
|
||||
}
|
||||
|
||||
s := query.Get("client_public")
|
||||
b, _ := hex.DecodeString(s)
|
||||
return b
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) AddPair(conn net.Conn, id string, public []byte, permissions byte) {
|
||||
log.Trace().Msgf("[homekit] %s: add pair id=%s public=%x perm=%d", conn.RemoteAddr(), id, public, permissions)
|
||||
|
||||
query := url.Values{
|
||||
"client_id": []string{id},
|
||||
"client_public": []string{hex.EncodeToString(public)},
|
||||
"permissions": []string{string('0' + permissions)},
|
||||
}
|
||||
if s.GetPair(conn, id) == nil {
|
||||
s.pairings = append(s.pairings, query.Encode())
|
||||
s.UpdateStatus()
|
||||
s.PatchConfig()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) DelPair(conn net.Conn, id string) {
|
||||
log.Trace().Msgf("[homekit] %s: del pair id=%s", conn.RemoteAddr(), id)
|
||||
|
||||
id = "client_id=" + id
|
||||
for i, pairing := range s.pairings {
|
||||
if !strings.Contains(pairing, id) {
|
||||
continue
|
||||
}
|
||||
|
||||
s.pairings = append(s.pairings[:i], s.pairings[i+1:]...)
|
||||
s.UpdateStatus()
|
||||
s.PatchConfig()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) PatchConfig() {
|
||||
if err := app.PatchConfig([]string{"homekit", s.stream, "pairings"}, s.pairings); err != nil {
|
||||
log.Error().Err(err).Msgf(
|
||||
"[homekit] can't save %s pairings=%v", s.stream, s.pairings,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func calcName(name, seed string) string {
|
||||
if name != "" {
|
||||
return name
|
||||
|
||||
Reference in New Issue
Block a user