mirror of
				https://github.com/AlexxIT/go2rtc.git
				synced 2025-10-31 11:46:26 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			141 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package homekit
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"github.com/AlexxIT/go2rtc/cmd/app/store"
 | |
| 	"github.com/AlexxIT/go2rtc/cmd/streams"
 | |
| 	"github.com/AlexxIT/go2rtc/pkg/hap"
 | |
| 	"github.com/AlexxIT/go2rtc/pkg/hap/mdns"
 | |
| 	"net/http"
 | |
| 	"net/url"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| func apiHandler(w http.ResponseWriter, r *http.Request) {
 | |
| 	switch r.Method {
 | |
| 	case "GET":
 | |
| 		items := make([]interface{}, 0)
 | |
| 
 | |
| 		for name, src := range store.GetDict("streams") {
 | |
| 			if src := src.(string); strings.HasPrefix(src, "homekit") {
 | |
| 				u, err := url.Parse(src)
 | |
| 				if err != nil {
 | |
| 					continue
 | |
| 				}
 | |
| 				device := Device{
 | |
| 					Name:   name,
 | |
| 					Addr:   u.Host,
 | |
| 					Paired: true,
 | |
| 				}
 | |
| 				items = append(items, device)
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		for info := range mdns.GetAll() {
 | |
| 			if !strings.HasSuffix(info.Name, mdns.Suffix) {
 | |
| 				continue
 | |
| 			}
 | |
| 			name := info.Name[:len(info.Name)-len(mdns.Suffix)]
 | |
| 			device := Device{
 | |
| 				Name: strings.ReplaceAll(name, "\\", ""),
 | |
| 				Addr: fmt.Sprintf("%s:%d", info.AddrV4, info.Port),
 | |
| 			}
 | |
| 			for _, field := range info.InfoFields {
 | |
| 				switch field[:2] {
 | |
| 				case "id":
 | |
| 					device.ID = field[3:]
 | |
| 				case "md":
 | |
| 					device.Model = field[3:]
 | |
| 				case "sf":
 | |
| 					device.Paired = field[3] == '0'
 | |
| 				}
 | |
| 			}
 | |
| 			items = append(items, device)
 | |
| 		}
 | |
| 
 | |
| 		_ = json.NewEncoder(w).Encode(items)
 | |
| 
 | |
| 	case "POST":
 | |
| 		// TODO: post params...
 | |
| 
 | |
| 		id := r.URL.Query().Get("id")
 | |
| 		pin := r.URL.Query().Get("pin")
 | |
| 		name := r.URL.Query().Get("name")
 | |
| 		if err := hkPair(id, pin, name); err != nil {
 | |
| 			log.Error().Err(err).Caller().Send()
 | |
| 			_, err = w.Write([]byte(err.Error()))
 | |
| 		}
 | |
| 
 | |
| 	case "DELETE":
 | |
| 		src := r.URL.Query().Get("src")
 | |
| 		if err := hkDelete(src); err != nil {
 | |
| 			log.Error().Err(err).Caller().Send()
 | |
| 			_, err = w.Write([]byte(err.Error()))
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func hkPair(deviceID, pin, name string) (err error) {
 | |
| 	var conn *hap.Conn
 | |
| 
 | |
| 	if conn, err = hap.Pair(deviceID, pin); err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	streams.New(name, conn.URL())
 | |
| 
 | |
| 	dict := store.GetDict("streams")
 | |
| 	dict[name] = conn.URL()
 | |
| 
 | |
| 	return store.Set("streams", dict)
 | |
| }
 | |
| 
 | |
| func hkDelete(name string) (err error) {
 | |
| 	dict := store.GetDict("streams")
 | |
| 	for key, rawURL := range dict {
 | |
| 		if key != name {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		var conn *hap.Conn
 | |
| 
 | |
| 		if conn, err = hap.NewConn(rawURL.(string)); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if err = conn.Dial(); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		go func() {
 | |
| 			if err = conn.Handle(); err != nil {
 | |
| 				log.Warn().Err(err).Caller().Send()
 | |
| 			}
 | |
| 		}()
 | |
| 
 | |
| 		if err = conn.ListPairings(); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		if err = conn.DeletePairing(conn.ClientID); err != nil {
 | |
| 			log.Error().Err(err).Caller().Send()
 | |
| 		}
 | |
| 
 | |
| 		delete(dict, name)
 | |
| 
 | |
| 		return store.Set("streams", dict)
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type Device struct {
 | |
| 	ID     string `json:"id"`
 | |
| 	Name   string `json:"name"`
 | |
| 	Addr   string `json:"addr"`
 | |
| 	Model  string `json:"model"`
 | |
| 	Paired bool   `json:"paired"`
 | |
| 	//Type    string `json:"type"`
 | |
| }
 | 
