mirror of
				https://github.com/XZB-1248/Spark
				synced 2025-10-31 11:06:17 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			205 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package core
 | |
| 
 | |
| import (
 | |
| 	"Spark/client/common"
 | |
| 	"Spark/client/config"
 | |
| 	"Spark/modules"
 | |
| 	"Spark/utils"
 | |
| 	"encoding/hex"
 | |
| 	"errors"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"os/exec"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	ws "github.com/gorilla/websocket"
 | |
| 	"github.com/kataras/golog"
 | |
| )
 | |
| 
 | |
| // simplified type of map
 | |
| type smap map[string]any
 | |
| 
 | |
| var stop bool
 | |
| var (
 | |
| 	errNoSecretHeader = errors.New(`can not find secret header`)
 | |
| )
 | |
| 
 | |
| func Start() {
 | |
| 	for !stop {
 | |
| 		var err error
 | |
| 		if common.WSConn != nil {
 | |
| 			common.Mutex.Lock()
 | |
| 			common.WSConn.Close()
 | |
| 			common.Mutex.Unlock()
 | |
| 		}
 | |
| 		common.Mutex.Lock()
 | |
| 		common.WSConn, err = connectWS()
 | |
| 		common.Mutex.Unlock()
 | |
| 		if err != nil && !stop {
 | |
| 			golog.Error(`Connection error: `, err)
 | |
| 			<-time.After(3 * time.Second)
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		err = reportWS(common.WSConn)
 | |
| 		if err != nil && !stop {
 | |
| 			golog.Error(`Register error: `, err)
 | |
| 			<-time.After(3 * time.Second)
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		checkUpdate(common.WSConn)
 | |
| 
 | |
| 		err = handleWS(common.WSConn)
 | |
| 		if err != nil && !stop {
 | |
| 			golog.Error(`Execution error: `, err)
 | |
| 			<-time.After(3 * time.Second)
 | |
| 			continue
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func connectWS() (*common.Conn, error) {
 | |
| 	wsConn, wsResp, err := ws.DefaultDialer.Dial(config.GetBaseURL(true)+`/ws`, http.Header{
 | |
| 		`UUID`: []string{config.Config.UUID},
 | |
| 		`Key`:  []string{config.Config.Key},
 | |
| 	})
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	header, find := wsResp.Header[`Secret`]
 | |
| 	if !find || len(header) == 0 {
 | |
| 		return nil, errNoSecretHeader
 | |
| 	}
 | |
| 	secret, err := hex.DecodeString(header[0])
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return common.CreateConn(wsConn, secret), nil
 | |
| }
 | |
| 
 | |
| func reportWS(wsConn *common.Conn) error {
 | |
| 	device, err := GetDevice()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	pack := modules.CommonPack{Act: `report`, Data: *device}
 | |
| 	err = wsConn.SendPack(pack)
 | |
| 	common.WSConn.SetWriteDeadline(time.Time{})
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	common.WSConn.SetReadDeadline(common.Now.Add(5 * time.Second))
 | |
| 	_, data, err := common.WSConn.ReadMessage()
 | |
| 	common.WSConn.SetReadDeadline(time.Time{})
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	data, err = utils.Decrypt(data, common.WSConn.GetSecret())
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	err = utils.JSON.Unmarshal(data, &pack)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if pack.Code != 0 {
 | |
| 		return errors.New(`${i18n|unknownError}`)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func checkUpdate(wsConn *common.Conn) error {
 | |
| 	if len(config.COMMIT) == 0 {
 | |
| 		return nil
 | |
| 	}
 | |
| 	resp, err := common.HTTP.R().
 | |
| 		SetBody(config.CfgBuffer).
 | |
| 		SetQueryParam(`os`, runtime.GOOS).
 | |
| 		SetQueryParam(`arch`, runtime.GOARCH).
 | |
| 		SetQueryParam(`commit`, config.COMMIT).
 | |
| 		SetHeader(`Secret`, wsConn.GetSecretHex()).
 | |
| 		Send(`POST`, config.GetBaseURL(false)+`/api/client/update`)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	if resp == nil {
 | |
| 		return errors.New(`${i18n|unknownError}`)
 | |
| 	}
 | |
| 	if strings.HasPrefix(resp.GetContentType(), `application/octet-stream`) {
 | |
| 		body := resp.Bytes()
 | |
| 		if len(body) > 0 {
 | |
| 			selfPath, err := os.Executable()
 | |
| 			if err != nil {
 | |
| 				selfPath = os.Args[0]
 | |
| 			}
 | |
| 			err = os.WriteFile(selfPath+`.tmp`, body, 0755)
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			cmd := exec.Command(selfPath+`.tmp`, `--update`)
 | |
| 			err = cmd.Start()
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			stop = true
 | |
| 			wsConn.Close()
 | |
| 			os.Exit(0)
 | |
| 		}
 | |
| 		return nil
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func handleWS(wsConn *common.Conn) error {
 | |
| 	errCount := 0
 | |
| 	for {
 | |
| 		_, data, err := wsConn.ReadMessage()
 | |
| 		if err != nil {
 | |
| 			golog.Error(err)
 | |
| 			return nil
 | |
| 		}
 | |
| 		data, err = utils.Decrypt(data, wsConn.GetSecret())
 | |
| 		if err != nil {
 | |
| 			golog.Error(err)
 | |
| 			errCount++
 | |
| 			if errCount > 3 {
 | |
| 				break
 | |
| 			}
 | |
| 			continue
 | |
| 		}
 | |
| 		pack := modules.Packet{}
 | |
| 		utils.JSON.Unmarshal(data, &pack)
 | |
| 		if err != nil {
 | |
| 			golog.Error(err)
 | |
| 			errCount++
 | |
| 			if errCount > 3 {
 | |
| 				break
 | |
| 			}
 | |
| 			continue
 | |
| 		}
 | |
| 		errCount = 0
 | |
| 		if pack.Data == nil {
 | |
| 			pack.Data = smap{}
 | |
| 		}
 | |
| 		go handleAct(pack, wsConn)
 | |
| 	}
 | |
| 	wsConn.Close()
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func handleAct(pack modules.Packet, wsConn *common.Conn) {
 | |
| 	if act, ok := handlers[pack.Act]; !ok {
 | |
| 		wsConn.SendCallback(modules.Packet{Code: 1, Msg: `${i18n|actionNotImplemented}`}, pack)
 | |
| 	} else {
 | |
| 		defer func() {
 | |
| 			if r := recover(); r != nil {
 | |
| 				golog.Error(`Panic: `, r)
 | |
| 			}
 | |
| 		}()
 | |
| 		act(pack, wsConn)
 | |
| 	}
 | |
| }
 | 
