Commit 90c6e60d authored by wei.xuan's avatar wei.xuan

Merge branch 'v0.0.1-beta2' into 'master'

feat: opt

See merge request !1
parents bab9c2e0 ee707a01
.idea
echo-cli
dist/config.yaml
\ No newline at end of file
dist/config.yaml
dist
majora-cli
\ No newline at end of file
project_name: majora-go
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
# you may remove this if you don't need go generate
- go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
- netbsd
- openbsd
goarch:
- amd64
- arm
- arm64
goarm:
- 6
- 7
binary: majora-cli
ignore:
- goos: darwin
goarch: 386
- goos: windows
goarch: 386
- goos: windows
goarch: arm
- goos: windows
goarch: arm64
asmflags:
- all=-trimpath={{.Env.GOPATH}}
gcflags:
- all=-trimpath={{.Env.GOPATH}}
ldflags:
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
archives:
- replacements:
darwin: Darwin
linux: Linux
windows: Windows
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
UNAME := $(shell uname)
# LDFLAGS := '-s -w --extldflags "-static -fpic"'
LDFLAGS := '-s -w --extldflags "-fpic"'
# BUILD_MODE := '--buildmode=c-archive'
BUILD_MODE := '--buildmode=c-shared'
BUILD_CMD := go build -trimpath -ldflags $(LDFLAGS) $(BUILD_MODE)
LIB := lib/sdk.go
# linux 64
cc_linux := /home/xuan/musl-cross/x86_64-linux/bin/x86_64-linux-musl-gcc
cxx_linux := /home/xuan/musl-cross/x86_64-linux/bin/x86_64-linux-musl-g++
# arm64
cc_aarch64 := /home/xuan/musl-cross/aarch64-linux/bin/aarch64-linux-musl-gcc
cxx_aarch64 := /home/xuan/musl-cross/aarch64-linux/bin/aarch64-linux-musl-g++
# 树莓派
cc_armhf_linux := /home/xuan/musl-cross/arm-linux-musleabihf/bin/arm-linux-musleabihf-gcc
cxx_armhf_linux := /home/xuan/musl-cross/arm-linux-musleabihf/bin/arm-linux-musleabihf-g++
# armv6
cc_armv6_linux := /home/xuan/musl-cross/armv6-linux-musleabi/bin/armv6-linux-musleabi-gcc
cxx_armv6_linux := /home/xuan/musl-cross/armv6-linux-musleabi/bin/armv6-linux-musleabi-g++
# win64
cc_win := /home/xuan/musl-cross/i686-w64-mingw32/bin/i686-w64-mingw32-gcc
cxx_win := /home/xuan/musl-cross/i686-w64-mingw32/bin/i686-w64-mingw32-g++
buildlocal:
CGO_ENABLE=0 go build -trimpath -ldflags '-w -s' -o majora-cli
releaselocal:
goreleaser build --rm-dist --snapshot --single-target
releaseall:
goreleaser build --rm-dist --snapshot
sdk_mac:
CGO_ENABLED=1 go build -trimpath -ldflags $(LDFLAGS) $(BUILD_MODE) -o lib/libmajora_mac.so $(LIB)
sdk_linux:
CGO_ENABLED=1 CC=${cc_linux} CXX=${cxx_linux} GOOS=linux GOARCH=amd64 $(BUILD_CMD) -o lib/libmajora_linux_amd64.so $(LIB)
sdk_aarch64:
CGO_ENABLED=1 CC=${cc_aarch64} CXX=${cxx_aarch64} GOOS=linux GOARCH=arm64 $(BUILD_CMD) -o lib/libmajora_linux_aarch64.so $(LIB)
sdk_armv6:
CGO_ENABLED=1 CC=${cc_armv6_linux} CXX=${cxx_armv6_linux} GOOS=linux GOARCH=arm $(BUILD_CMD) -o lib/libmajora_linux_armv6.so $(LIB)
sdk_armhf:
CGO_ENABLED=1 CC=${cc_armhf_linux} CXX=${cxx_armhf_linux} GOOS=linux GOARCH=arm $(BUILD_CMD) -o lib/libmajora_linux_aarch64.so $(LIB)
sdk_win:
CGO_ENABLED=1 CC=${cc_win} CXX=${cxx_win} GOOS=windows GOARCH=amd64 $(BUILD_CMD) -o lib/libmajora_win_amd64.dll $(LIB)
clean:
rm -fr dist
rm -fr majora-cli
rm -fr libmajora.so
rm -fr libmajora.h
#!/usr/bin/env bash
export GO111MODULE="on"
export GOPROXY="https://goproxy.cn,https://goproxy.io,direct"
export CGO_ENABLE=1
DATE=$(date "+%Y%m%d-%H%M%S")
mkdir "$1"
BINARY=majora
VERSION=$1
GOVER=latest
BUILDINFO="-X main.Version=$VERSION -X main.Date=$DATE"
EXTFLAG="--extldflags \"-static -fpic\""
OUTDIR=dist/$1
OUT=$OUTDIR/$BINARY-$1
TOKEN=Aau6PvRI4o0OTYrgpQHzxG7qEDkADx6CaUAJV2
TOKENONLINE=456734sdlasysdhf293r23r
echo "$OUTDIR"
echo "$OUT"
build_local() {
echo "build local..."
go build -a -trimpath -ldflags "-w -s $BUILDINFO" -o $BINARY
if [ $? -ne 0 ]; then
echo "build local fail"
exit 1
fi
echo "build success"
}
build_release() {
xgo -x -out "$OUT" -goproxy $GOPROXY -go $GOVER -ldflags="-s -w $EXTFLAG $BUILDINFO" /home/xuan/code/gcode/majora-go
}
upload() {
sudo chown -R xuan dist
cd "$OUTDIR"
for file in `ls | grep majora`; do
newfile=$(echo "${file}" | sed 's/-10.12//g;s/-4.0//g')
echo "uploading $newfile ..."
curl -F file=@"${file}" -F filename="${newfile}" -F token=$TOKEN http://81.70.224.147:10010/version
curl -F file=@"${file}" -F filename="${newfile}" -F token=$TOKENONLINE https://oss.virjar.com/majora/bin
done
touch latest.txt
echo "$VERSION" > latest.txt
curl -F file=@latest.txt -F token=$TOKEN http://81.70.224.147:10010/version
curl -F file=@latest.txt -F token=$TOKENONLINE https://oss.virjar.com/majora/bin
}
build_local
build_release
upload
\ No newline at end of file
......@@ -14,20 +14,23 @@ import (
"virjar.com/majora-go/client"
"virjar.com/majora-go/common"
"virjar.com/majora-go/logger"
"virjar.com/majora-go/updater"
)
var (
logLevel int
pprof bool
natServer string
account string
dnsServer string
disableDNS bool
logLevel int
pprof bool
natServer string
account string
dnsServer string
disableDNS bool
localAddr string
disableUpdate bool
)
var (
version = "dev"
date = "unknown"
Version string
Date string
)
func init() {
......@@ -38,6 +41,8 @@ func init() {
flag.StringVar(&account, "account", "unknown", "account")
flag.StringVar(&dnsServer, "dnsServer", common.DNSServer, "custom dns server")
flag.BoolVar(&disableDNS, "disableDns", false, "disable default dns server")
flag.StringVar(&localAddr, "localIp", "", "bind local ip")
flag.BoolVar(&disableUpdate, "disableUpdate", false, "disable self update")
flag.Parse()
}
......@@ -63,10 +68,23 @@ func initPprof() {
}
}
func update() {
if disableUpdate {
return
}
if _, err := updater.Update("majora", Version); err != nil {
logger.Error().Msgf("check update error %+s", err.Error())
}
}
func main() {
initPprof()
logger.SetLogLevel(logLevel)
logger.Info().Msgf("current version %s, build at %s", version, date)
logger.Info().Msgf("current Version %s, build at %s", Version, Date)
update()
logger.Info().Msgf("hostinfo os:%s, arch:%s", runtime.GOOS, runtime.GOARCH)
client.NewClient(client.WithNatServerAddr(natServer), client.WithAccount(account))
client.NewClient(client.WithNatServerAddr(natServer),
client.WithLocalIP(localAddr),
client.WithAccount(account))
}
......@@ -55,8 +55,7 @@ func (client *Client) register() {
packet := protocol.TypeRegister.CreatePacket()
packet.Extra = client.Options.ClientID
packet.Data = protocol.EncodeExtra(client.Options.ExtraInfo)
encode, _ := client.Codec.Encode(packet)
if err := client.WriteAndFlush(encode); err != nil {
if err := client.WriteAndFlush(packet); err != nil {
logger.Error().Msgf("register to nat server with error %s", err.Error())
} else {
logger.Info().Msg("register to nat server success")
......@@ -68,7 +67,6 @@ func (client *Client) handleNatEvent() {
reader := bufio.NewReader(client.natTunnel.Load().(net.Conn))
majoraPacket, err := client.Codec.Decode(reader)
if errors.Is(err, io.EOF) {
logger.Error().Msgf("*********disconnect******")
client.reConnect()
continue
}
......@@ -83,15 +81,15 @@ func (client *Client) handleNatEvent() {
case protocol.TypeHeartbeat:
client.handleHeartbeatMessage()
case protocol.TypeConnect:
go client.handleConnect(majoraPacket)
client.handleConnect(majoraPacket)
case protocol.TypeTransfer:
go client.handleTransfer(majoraPacket)
client.handleTransfer(majoraPacket)
case protocol.TypeDisconnect:
go client.handleDisconnectMessage(majoraPacket)
client.handleDisconnectMessage(majoraPacket)
case protocol.TypeControl:
go client.handleControlMessage(majoraPacket)
client.handleControlMessage(majoraPacket)
case protocol.TypeDestroy:
go client.handleDestroyMessage()
client.handleDestroyMessage()
}
}
}
......@@ -127,11 +125,19 @@ func (client *Client) connect() {
panic("invalid nat host/port info")
}
conn, err := net.DialTimeout(common.TCP, hostPort, common.ConnTimeout)
dialer := net.Dialer{
Timeout: common.ConnTimeout,
}
if client.Options.LocalAddr != nil {
dialer.LocalAddr = client.Options.LocalAddr
}
conn, err := dialer.Dial(common.TCP, hostPort)
if err != nil || conn == nil {
panic(fmt.Sprintf("connect to nathost %s with err %s", hostPort, err.Error()))
}
logger.Info().Msgf("connect to nathost %s success ...", hostPort)
logger.Info().Msgf("connect from %s to nathost %s success ...", dialer.LocalAddr.String(), hostPort)
client.natTunnel.Store(conn)
}
......@@ -17,56 +17,65 @@ func (client *Client) handleHeartbeatMessage() {
go func() {
logger.Debug().Msg("receive heartbeat message from nat server")
packet := protocol.TypeHeartbeat.CreatePacket()
encode, _ := client.Codec.Encode(packet)
if err := client.WriteAndFlush(encode); err != nil {
if err := client.WriteAndFlush(packet); err != nil {
logger.Error().Msgf("flush heart beat message error %s", err.Error())
}
}()
}
func (client *Client) handleConnect(packet *protocol.MajoraPacket) {
if len(packet.Extra) == 0 {
client.disconnect(packet, "empty extra")
return
}
go func(packet *protocol.MajoraPacket) {
if len(packet.Extra) == 0 {
client.closeVirtualConnection(packet, "empty extra")
return
}
hostPort := strings.Split(packet.Extra, ":")
hostPort := strings.Split(packet.Extra, ":")
if len(hostPort) != 2 {
client.disconnect(packet, "invalid extra "+packet.Extra)
return
}
logger.Info().Msgf("handleConnect to %s", hostPort)
var (
conn net.Conn
err error
)
addr := fmt.Sprintf("%s:%s", hostPort[0], hostPort[1])
conn, err = net.DialTimeout(common.TCP, addr, common.ConnTimeout)
if err != nil {
client.disconnect(packet, "connect to target host error "+err.Error())
return
}
if len(hostPort) != 2 {
client.closeVirtualConnection(packet, "invalid extra "+packet.Extra)
return
}
logger.Info().Msgf("handleConnect to %s", hostPort)
client.AddConnection(packet, conn)
majoraPacket := protocol.TypeConnectReady.CreatePacket()
majoraPacket.SerialNumber = packet.SerialNumber
majoraPacket.Extra = client.Options.ClientID
var (
conn net.Conn
err error
)
encode, _ := client.Codec.Encode(majoraPacket)
if err := client.WriteAndFlush(encode); err != nil {
logger.Error().Msgf("handleConnect message error %s", err.Error())
_ = conn.Close()
return
}
client.handleConnection(conn, packet)
addr := fmt.Sprintf("%s:%s", hostPort[0], hostPort[1])
dialer := net.Dialer{
Timeout: common.ConnTimeout,
}
if client.Options.LocalAddr != nil {
dialer.LocalAddr = client.Options.LocalAddr
}
conn, err = dialer.Dial(common.TCP, addr)
if err != nil {
client.closeVirtualConnection(packet, "connect to target host error "+err.Error())
return
}
client.AddConnection(packet, conn)
majoraPacket := protocol.TypeConnectReady.CreatePacket()
majoraPacket.SerialNumber = packet.SerialNumber
majoraPacket.Extra = client.Options.ClientID
if err := client.WriteAndFlush(majoraPacket); err != nil {
logger.Error().Msgf("handleConnect message error %s", err.Error())
_ = conn.Close()
return
}
client.handleConnection(conn, packet)
}(packet)
}
func (client *Client) WriteAndFlush(packet []byte) error {
func (client *Client) WriteAndFlush(packet *protocol.MajoraPacket) error {
writer := bufio.NewWriter(client.natTunnel.Load().(net.Conn))
if _, err := writer.Write(packet); err != nil {
encode := client.Codec.Encode(packet)
if _, err := writer.Write(encode); err != nil {
logger.Warn().Msgf("write to nat server error err:%+v", err)
return err
}
......@@ -74,16 +83,18 @@ func (client *Client) WriteAndFlush(packet []byte) error {
}
func (client *Client) handleTransfer(packet *protocol.MajoraPacket) {
conn, ok := client.GetConnection(packet, "handleTransfer")
// 如何把这个错误告诉服务端
if !ok {
return
}
go func(packet *protocol.MajoraPacket) {
conn, ok := client.GetConnection(packet, "handleTransfer")
// 如何把这个错误告诉服务端
if !ok {
return
}
if cnt, err := conn.Write(packet.Data); err != nil {
logger.Warn().Msgf("write with error cnt=%d|err=%+v", cnt, err)
client.removeConnection(packet, "write_error")
}
if cnt, err := conn.Write(packet.Data); err != nil {
logger.Warn().Msgf("write with error cnt=%d|err=%+v", cnt, err)
client.removeConnection(packet, "write_error")
}
}(packet)
}
func (client *Client) handleConnection(conn net.Conn, packet *protocol.MajoraPacket) {
......@@ -109,32 +120,32 @@ func (client *Client) handleConnection(conn net.Conn, packet *protocol.MajoraPac
pack := protocol.TypeTransfer.CreatePacket()
pack.Data = buf
pack.SerialNumber = packet.SerialNumber
encode, _ := client.Codec.Encode(pack)
if err = client.WriteAndFlush(encode); err != nil {
if err = client.WriteAndFlush(pack); err != nil {
logger.Error().Msgf("write to nat server error %+v", err)
}
}
}
func (client *Client) handleDisconnectMessage(packet *protocol.MajoraPacket) {
client.removeConnection(packet, "from_server")
go func() {
client.removeConnection(packet, "from_server")
}()
}
func (client *Client) handleControlMessage(_ *protocol.MajoraPacket) {
logger.Debug().Msg("handleControlMessage ")
go func() {
logger.Debug().Msg("handleControlMessage ")
}()
}
// handleDestroyMessage 是直接关闭nat server ?
func (client *Client) handleDestroyMessage() {
}
func (client *Client) disconnect(packet *protocol.MajoraPacket, msg string) {
logger.Warn().Msgf("disconnect to server %s", msg)
disconnectCmd := protocol.TypeDisconnect.CreatePacket()
disconnectCmd.SerialNumber = packet.SerialNumber
disconnectCmd.Data = []byte(msg)
encode, _ := client.Codec.Encode(disconnectCmd)
_ = client.WriteAndFlush(encode)
go func() {
conn, ok := client.natTunnel.Load().(net.Conn)
if ok && conn != nil {
_ = conn.Close()
}
}()
}
func (client *Client) AddConnection(packet *protocol.MajoraPacket, conn net.Conn) {
......@@ -160,8 +171,7 @@ func (client *Client) removeConnection(packet *protocol.MajoraPacket, reason str
majoraPacket.SerialNumber = packet.SerialNumber
majoraPacket.Data = []byte(client.Options.ClientID)
encode, _ := client.Codec.Encode(majoraPacket)
if err := client.WriteAndFlush(encode); err != nil {
if err := client.WriteAndFlush(majoraPacket); err != nil {
logger.Warn().Msgf("flush to nat server error %s", err.Error())
}
}
......@@ -179,3 +189,14 @@ func (client *Client) GetConnection(packet *protocol.MajoraPacket, step string)
conn, ok = load.(net.Conn)
return
}
func (client *Client) closeVirtualConnection(packet *protocol.MajoraPacket, msg string) {
logger.Warn().Msgf("disconnect to server %s", msg)
majoraPacket := protocol.TypeDisconnect.CreatePacket()
majoraPacket.SerialNumber = packet.SerialNumber
majoraPacket.Extra = client.Options.ClientID
if err := client.WriteAndFlush(packet); err != nil {
logger.Error().Msgf("closeVirtualConnection with error %+v", err)
}
}
package client
import (
"net"
"virjar.com/majora-go/common"
)
......@@ -11,6 +13,7 @@ type (
NatHostPort string
ClientID string
Account string
LocalAddr net.Addr
ExtraInfo Extra
}
......@@ -34,3 +37,12 @@ func WithAccount(account string) Option {
options.ExtraInfo[common.ExtrakeyUser] = account
}
}
func WithLocalIP(ip string) Option {
return func(options *Options) {
options.LocalAddr = &net.TCPAddr{
IP: net.ParseIP(ip),
Port: 0,
}
}
}
......@@ -13,9 +13,7 @@ const (
TypeSize = 1
ExtraSize = 1
SerialNumberSize = 8
KeyLenSize = 1
ValueLenSize = 1
MAGIC = int64(0x6D616A6F72613031)
MAGIC = int64(0x6D616A6F72613031)
)
const (
......@@ -38,9 +36,9 @@ const (
)
var (
NilPacketError = errors.New("packet is nil")
InvalidSizeError = errors.New("invalid size")
InvalidMagicError = errors.New("invalid magic")
ErrNilPacket = errors.New("packet is nil")
ErrInvalidSize = errors.New("invalid size")
ErrInvalidMagic = errors.New("invalid magic")
)
func ConvertInt32ToBytes(input int32) []byte {
......
package common
const (
DNSServer = "114.114.114.114:53"
)
package common
const (
DNSServer = "114.114.114.114:53"
)
const (
UpdateServer = "http://81.70.224.147:10010"
Latest = "latest.txt"
UpdateBinaryPath = "/version/"
// VersionTpl majora-v0.0.1-linux-arm64 name-version-os-arch
VersionTpl = "%s-%s-%s-%s"
)
const (
DefaultMode = 0755
)
#!/usr/bin/env bash
cd `dirname $0`
# only runing on virjar PC
cp -r dist/* ~/Desktop/file_server/majora/bin/
cp -r lib/*.h ~/Desktop/file_server/majora/sdk/
cp -r lib/*.so ~/Desktop/file_server/majora/sdk/
......@@ -3,6 +3,7 @@ module virjar.com/majora-go
go 1.17
require (
github.com/blang/semver/v4 v4.0.0
github.com/google/uuid v1.3.0
github.com/rs/zerolog v1.25.0
)
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
......
......@@ -9,6 +9,11 @@ import (
//export NewDefClient
func NewDefClient(asyn C.int, account *C.char) {
options := client.NewOptions()
newAccount := C.GoString(account)
if len(newAccount) > 0 {
options.Account = newAccount
}
cli := &client.Client{Options: options, Codec: protocol.NewDefCodec()}
if int(asyn) > 0 {
......@@ -23,12 +28,18 @@ func NewClientWithNatServer(addr *C.char, clientID *C.char, asyn C.int, account
options := client.NewOptions()
newAddr := C.GoString(addr)
newClientID := C.GoString(clientID)
newAccount := C.GoString(account)
if len(newAddr) > 0 {
options.NatHostPort = newAddr
}
if len(newClientID) > 0 {
options.ClientID = newClientID
}
if len(newAccount) > 0 {
options.Account = newAccount
}
cli := &client.Client{Options: options, Codec: protocol.NewDefCodec()}
if int(asyn) > 0 {
go cli.StartUp()
......
......@@ -10,7 +10,7 @@ var (
type (
ICodec interface {
Encode(packet *MajoraPacket) ([]byte, error)
Encode(packet *MajoraPacket) []byte
Decode(reader *bufio.Reader) (*MajoraPacket, error)
}
......@@ -27,7 +27,7 @@ func NewDefCodec() *DefCodec {
}
}
func (d *DefCodec) Encode(packet *MajoraPacket) ([]byte, error) {
func (d *DefCodec) Encode(packet *MajoraPacket) []byte {
return d.Encoder.Encode(packet)
}
......
......@@ -23,19 +23,19 @@ func (mpd *MajoraPacketDecoder) Decode(reader *bufio.Reader) (pack *MajoraPacket
}
if !common.ReadMagic(magicbs) {
return nil, common.InvalidMagicError
return nil, common.ErrInvalidMagic
}
frameLen, err := common.ReadInt32(reader)
if err != nil {
return nil, common.InvalidSizeError
return nil, common.ErrInvalidSize
}
// type
msgType, err := common.ReadByte(reader)
if err != nil {
logger.Error().Msgf("read type error %+v", err)
return nil, common.InvalidSizeError
return nil, common.ErrInvalidSize
}
pack = &MajoraPacket{}
pack.Ttype = MajoraPacketType(msgType)
......@@ -44,20 +44,20 @@ func (mpd *MajoraPacketDecoder) Decode(reader *bufio.Reader) (pack *MajoraPacket
pack.SerialNumber, err = common.ReadInt64(reader)
if err != nil {
logger.Error().Msgf("read type error %+v", err)
return nil, common.InvalidSizeError
return nil, common.ErrInvalidSize
}
// extra size
extraSize, err := common.ReadByte(reader)
if err != nil {
logger.Error().Msgf("read type error %+v", err)
return nil, common.InvalidSizeError
return nil, common.ErrInvalidSize
}
extra, err := common.ReadN(int(extraSize), reader)
if err != nil {
logger.Error().Msgf("read type error %+v", err)
return nil, common.InvalidSizeError
return nil, common.ErrInvalidSize
}
pack.Extra = string(extra)
......@@ -65,7 +65,7 @@ func (mpd *MajoraPacketDecoder) Decode(reader *bufio.Reader) (pack *MajoraPacket
dataSize := int(frameLen) - common.TypeSize - common.SerialNumberSize - common.ExtraSize - int(extraSize)
if dataSize < 0 {
logger.Error().Msgf("read type error %+v", err)
return nil, common.InvalidSizeError
return nil, common.ErrInvalidSize
}
if dataSize > 0 {
......
......@@ -7,15 +7,15 @@ import (
)
type Encoder interface {
Encode(*MajoraPacket) ([]byte, error)
Encode(*MajoraPacket) []byte
}
type MajoraPacketEncoder struct {
}
func (s *MajoraPacketEncoder) Encode(packet *MajoraPacket) ([]byte, error) {
func (s *MajoraPacketEncoder) Encode(packet *MajoraPacket) []byte {
if packet == nil {
return nil, common.NilPacketError
return nil
}
bodyLength := common.TypeSize + common.SerialNumberSize + common.ExtraSize
......@@ -27,7 +27,6 @@ func (s *MajoraPacketEncoder) Encode(packet *MajoraPacket) ([]byte, error) {
innerBuf = make([]byte, 0, bodyLength+8+4)
// todo 池化提高性能
buffer = bytes.NewBuffer(innerBuf)
err error
)
// magic 8byte
......@@ -51,5 +50,5 @@ func (s *MajoraPacketEncoder) Encode(packet *MajoraPacket) ([]byte, error) {
if len(packet.Data) > 0 {
buffer.Write(packet.Data)
}
return buffer.Bytes(), err
return buffer.Bytes()
}
package updater
import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"os/exec"
"runtime"
"strings"
"github.com/blang/semver/v4"
"virjar.com/majora-go/common"
"virjar.com/majora-go/logger"
)
// getBinary 下载二进制
func getBinary(name, os, arch, version string) (io.ReadCloser, error) {
fileName := fmt.Sprintf(common.VersionTpl, name, version, os, arch)
if os == "windows" {
fileName += ".exe"
}
url := common.UpdateServer + common.UpdateBinaryPath + fileName
logger.Debug().Msgf("getBinary url %s, filename %s", url, fileName)
body, err := http.DefaultClient.Get(url)
if err != nil {
return nil, err
}
return body.Body, nil
}
func downloadFile(name, os, arch, version string, f *os.File) error {
binary, err := getBinary(name, os, arch, version)
if err != nil {
return err
}
defer func(binary io.ReadCloser) {
_ = binary.Close()
}(binary)
body, err := ioutil.ReadAll(binary)
if err != nil {
return err
}
cnt, err := f.Write(body)
if err != nil {
return err
}
if cnt != len(body) {
return errors.New("write to file is not enough")
}
return nil
}
func rename(src, dst string) error {
if err := os.Chmod(src, common.DefaultMode); err != nil {
return err
}
if err := os.Rename(src, dst); err != nil {
return err
}
logger.Debug().Msgf("rename %s to %s", src, dst)
return nil
}
func restart() {
cmd := exec.Command(os.Args[0], os.Args[1:]...) //nolint:gosec
cmd.Env = os.Environ()
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
logger.Debug().Msgf("restart ... %+v", cmd)
if err := cmd.Run(); err != nil {
logger.Error().Msgf("restart error %+v", err)
}
}
func UpdateCore(name, latestVer, targetFile string) (bool, error) {
tf, err := ioutil.TempFile("", "")
if err != nil {
logger.Debug().Msgf("UpdateCore TempFile with error %s", err.Error())
return false, err
}
if err := downloadFile(name, runtime.GOOS, runtime.GOARCH, latestVer, tf); err != nil {
logger.Debug().Msgf("UpdateCore downloadFile with error %s", err.Error())
return false, err
}
if err := tf.Close(); err != nil {
logger.Debug().Msgf("UpdateCore tf close with error %s", err.Error())
return false, err
}
if err := rename(tf.Name(), targetFile); err != nil {
return false, err
}
restart()
return true, nil
}
func getLatestVersion() (string, error) {
url := common.UpdateServer + common.UpdateBinaryPath + common.Latest
logger.Debug().Msgf("getLatestVersion from %s", url)
resp, err := http.DefaultClient.Get(url) //nolint:bodyclose
if err != nil || resp == nil {
return "", err
}
defer func(Body io.ReadCloser) {
_ = Body.Close()
}(resp.Body)
if resp.StatusCode != http.StatusOK {
logger.Error().Msgf("get latest version with error %s->%d", url, resp.StatusCode)
return "", nil
}
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return strings.ReplaceAll(string(bytes), "\n", ""), nil
}
func needUpdate(curVer string) (bool, string) {
latestVer, err := getLatestVersion()
if err != nil {
logger.Error().Msgf("getLatestVersion with error %s", err.Error())
return false, ""
}
if len(latestVer) == 0 {
logger.Error().Msgf("getLatestVersion with empty")
return false, ""
}
if curVer[0] == 'v' || curVer[0] == 'V' {
curVer = curVer[1:]
}
latest := latestVer
if latestVer[0] == 'v' || latestVer[0] == 'V' {
latest = latest[1:]
}
cur, _ := semver.Make(curVer)
next, _ := semver.Make(latest)
logger.Debug().Msgf("curVer %s->cur %s, latestVer %s->next %s", curVer, cur, latest, next)
return cur.Compare(next) < 0, latestVer
}
// Update update to the latest version
func Update(name, curVer string) (bool, error) {
// get current exec path
executable, err := os.Executable()
if err != nil {
return false, err
}
logger.Debug().Msgf("current exec info %s", executable)
// check has new version
needUpdate, latestVer := needUpdate(curVer)
logger.Debug().Msgf("curVer %s, latestVer %s, need update %v", curVer, latestVer, needUpdate)
if !needUpdate {
logger.Debug().Msgf("no need update ...")
return false, nil
}
updateStatus, err := UpdateCore(name, latestVer, executable)
if err != nil {
logger.Error().Msgf("update to latest version with error %s", err)
return false, err
}
logger.Info().Msgf("update from %s to %s with success %v", curVer, latestVer, updateStatus)
return updateStatus, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment