package azure import ( "crypto/md5" "encoding/hex" "errors" "flag" "fmt" "io" "os" "os/exec" "path" "runtime" "sort" "strconv" "strings" "syscall" "time" "repositories.action2quare.com/ayo/gocommon/logger" "go.mongodb.org/mongo-driver/bson" ) func SortVersions(versions []string) []string { sort.Slice(versions, func(i, j int) bool { leftnum := 0 for _, iv := range strings.Split(versions[i], ".") { n, _ := strconv.Atoi(iv) leftnum += leftnum<<8 + n } rightnum := 0 for _, iv := range strings.Split(versions[j], ".") { n, _ := strconv.Atoi(iv) rightnum += rightnum<<8 + n } return leftnum < rightnum }) return versions } const ( HoustonStatPoolCount = int(10) ) type HoustonStatReport struct { Region string `json:"region"` FreeMemory float64 `json:"freeMemory"` FreePercent float64 `json:"freePercent"` CPUUsage float64 `json:"cpuUsage"` PlayingUsers int `json:"users"` PlayingSessions int `json:"sessions"` } var prefetchptr = flag.Bool("prefetch", false, "") func NeedPrefetch() bool { return *prefetchptr } var ErrUpdateUnnecessary = errors.New("binary is already latest") func SelfUpdateUsingScript(replycache *MessageReplyCache, graph *Graph, patchroot string, force bool) (err error) { // 1. 다운로드 var linkfilearg string if replycache != nil { if replycache.ReplyWrap == nil { hostname, _ := os.Hostname() replycache.ReplyWrap = replycache.SourceActivity().MakeWrap().WithPrefix(hostname) } linkfile := replycache.Serialize() linkfilearg = fmt.Sprintf("-updatelink=%s", linkfile) } currentexe, _ := os.Executable() currentexe = strings.ReplaceAll(currentexe, "\\", "/") exefile := path.Base(currentexe) if runtime.GOOS == "windows" && !strings.HasSuffix(exefile, ".exe") { exefile += ".exe" } newbinary := fmt.Sprintf("%s.%s", exefile, time.Now().Format("2006.01.02-15.04.05")) downloadurl := path.Join(patchroot, exefile) err = graph.DownloadFile(downloadurl, newbinary) if err != nil { return } _, err = os.Stat(newbinary) if os.IsNotExist(err) { err = errors.New("다운로드 실패 : " + newbinary) return } if !force { currentfile, e := os.Open(currentexe) if e != nil { return e } defer currentfile.Close() hash1 := md5.New() _, err = io.Copy(hash1, currentfile) if err != nil { return } currentHash := hex.EncodeToString(hash1.Sum(nil)) nextfile, e := os.Open(newbinary) if e != nil { return e } defer nextfile.Close() hash2 := md5.New() _, err = io.Copy(hash2, nextfile) if err != nil { return } nextHash := hex.EncodeToString(hash2.Sum(nil)) if currentHash == nextHash { // 해시가 같으니까 업데이트 할 필요가 없다. return ErrUpdateUnnecessary } } var scriptfileName string if runtime.GOOS == "linux" { scriptfileName = "selfupdate.sh" } else if runtime.GOOS == "windows" { scriptfileName = "selfupdate.bat" } scripturl := path.Join(patchroot, scriptfileName) if _, err = os.Stat(scriptfileName); os.IsExist(err) { err = os.Remove(scriptfileName) } else { err = nil } if err != nil { return } // 2. 스크립트 다운로드 err = graph.DownloadFile(scripturl, scriptfileName) if err != nil { return } var nextArgs []string for _, arg := range os.Args[1:] { // -updatelink : selfupdate시에 if !strings.HasPrefix(arg, "-updatelink=") && arg != "-prefetch" { nextArgs = append(nextArgs, arg) } } pid := strconv.Itoa(os.Getpid()) args := append([]string{ pid, newbinary, exefile, }, nextArgs...) if len(linkfilearg) > 0 { args = append(args, linkfilearg) } // 3. 독립 실행 if runtime.GOOS == "linux" { // 실행 가능한 권한 부여 err = os.Chmod(scriptfileName, 0777) if err != nil { return } // 실행 env := os.Environ() currentpath := path.Dir(currentexe) argv0 := path.Join(currentpath, scriptfileName) args = append([]string{"/bin/bash", argv0}, args...) err = syscall.Exec(args[0], args, env) if err != nil { return } } else if runtime.GOOS == "windows" { windowsargs := append([]string{ "/C", "start", scriptfileName, }, args...) cmd := exec.Command("cmd.exe", windowsargs...) err = cmd.Run() if err != nil { return } } return } var linkupdate = flag.String("updatelink", "", "") func ReplyUpdateComplete() { defer func() { r := recover() if r != nil { logger.Error(r) } }() if len(*linkupdate) > 0 { cache := DeserializeMessageReplyCache(*linkupdate) if cache != nil { os.Remove(*linkupdate) if cache.ReplyWrap != nil { cache.ReplyWrap.Update(cache.Replyaid, "업데이트 완료") } } } } // var objectIDCounter = readRandomUint32() // var processUnique = processUniqueBytes() // func processUniqueBytes() [5]byte { // var b [5]byte // _, err := io.ReadFull(rand.Reader, b[:]) // if err != nil { // panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %v", err)) // } // return b // } // func readRandomUint32() uint32 { // var b [4]byte // _, err := io.ReadFull(rand.Reader, b[:]) // if err != nil { // panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %v", err)) // } // return (uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24) // } type BsonMarshaler[T any] struct { val T } func NewBsonMarshaler[T any](val T) *BsonMarshaler[T] { return &BsonMarshaler[T]{ val: val, } } func (m *BsonMarshaler[T]) MarshalBinary() (data []byte, err error) { return bson.Marshal(m.val) }