Skip to content

Commit

Permalink
tweak: optimize fallback DeveloperDiskImage
Browse files Browse the repository at this point in the history
  • Loading branch information
bitxeno committed Jul 25, 2023
1 parent 3109792 commit fa392aa
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 86 deletions.
17 changes: 7 additions & 10 deletions manager/device_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ func (dm *DeviceManager) ReloadDevices() {
})
}

// 获取DeveloperDiskImage绑定信息,install/screenshot等功能
// 都需要先绑定DeveloperDiskImage才有权限操作
// Get AppleTV mounted information of DeveloperDiskImage
// install/screenshot function need mounted DeveloperDiskImage to operate.
func (dm *DeviceManager) GetMountImageInfo(udid string) (*model.UsbmuxdImage, error) {
devInfo, err := dm.GetUsbmuxdDevice(udid)
devInfo, err := dm.GetUsbmuxdDeviceInfo(udid)
if err != nil {
log.Err(err).Msg("Cannot get device info: ")
return nil, err
Expand All @@ -99,8 +99,7 @@ func (dm *DeviceManager) GetMountImageInfo(udid string) (*model.UsbmuxdImage, er
return imageInfo, nil
}

// AppleTV system has reboot, need restart usbmuxd????
// Error: lookup_image returned -256
// AppleTV system has reboot, need restart usbmuxd to fix lookup_image error
if strings.Contains(err.Error(), "lookup_image returned -256") {
if err = dm.RestartUsbmuxd(); err == nil {
time.Sleep(5 * time.Second)
Expand All @@ -115,7 +114,7 @@ func (dm *DeviceManager) GetMountImageInfo(udid string) (*model.UsbmuxdImage, er
return nil, err
}

func (dm *DeviceManager) GetUsbmuxdDevice(udid string) (*model.UsbmuxdDevice, error) {
func (dm *DeviceManager) GetUsbmuxdDeviceInfo(udid string) (*model.UsbmuxdDevice, error) {
cmd := exec.Command("ideviceinfo", "-u", udid, "-n")

data, err := cmd.CombinedOutput()
Expand All @@ -128,7 +127,6 @@ func (dm *DeviceManager) GetUsbmuxdDevice(udid string) (*model.UsbmuxdDevice, er
lines := strings.Split(output, "\n")
for _, v := range lines {
arr := strings.Split(v, ":")
// fmt.Println(arr)
if len(arr) == 2 {
switch strings.TrimSpace(arr[0]) {
case "ProductVersion":
Expand All @@ -149,23 +147,22 @@ func (dm *DeviceManager) CheckHasMountImage(udid string) (bool, error) {

data, err := cmd.CombinedOutput()
if err != nil {
return false, fmt.Errorf("%s\n%s", string(data), err.Error())
return false, fmt.Errorf("%s%s", string(data), err.Error())
}

output := string(data)
if strings.Contains(output, "ERROR") {
return false, fmt.Errorf("%s", output)
}

// fmt.Println(output)
return strings.Contains(output, "ImageSignature") && !strings.Contains(output, "ImageSignature[0]"), nil
}

func (dm *DeviceManager) RestartUsbmuxd() error {
cmd := exec.Command("/etc/init.d/usbmuxd", "restart")
data, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("%s\n%s", string(data), err.Error())
return fmt.Errorf("%s%s", string(data), err.Error())
}

return nil
Expand Down
35 changes: 19 additions & 16 deletions model/usbmuxd_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,40 @@ import (
type UsbmuxdImage struct {
Device UsbmuxdDevice

ImageMounted bool `json:"ImageMounted,omitempty"`
DeveloperDiskImageUrl string `json:"DeveloperDiskImageUrl,omitempty"`
DeveloperDiskImageVersion string `json:"DeveloperDiskImageVersion,omitempty"`
DowngradeDeveloperDiskImageUrl string `json:"DowngradeDeveloperDiskImageUrl,omitempty"`
DowngradeDeveloperDiskImageVersion string `json:"DowngradeDeveloperDiskImageVersion,omitempty"`
ImageMounted bool `json:"ImageMounted,omitempty"`
DeveloperDiskImageUrl string `json:"DeveloperDiskImageUrl,omitempty"`
DeveloperDiskImageVersion string `json:"DeveloperDiskImageVersion,omitempty"`
DeveloperDiskImageFallbackUrl string `json:"DeveloperDiskImageFallbackUrl,omitempty"`
DeveloperDiskImageFallbackVersion string `json:"DeveloperDiskImageFallbackVersion,omitempty"`
}

func NewUsbmuxdImage(device UsbmuxdDevice, imageSource string) *UsbmuxdImage {
arr := strings.Split(device.ProductVersion, ".")
version := ""
downgradeVersion := ""
FallbackVersion := ""
major := 0
minor := 0
if len(arr) < 2 {
major = utils.MustParseInt(arr[0])
minor = 0
version = fmt.Sprintf("%s.0", arr[0])
downgradeVersion = fmt.Sprintf("%d.%d", major-1, minor)
version = fmt.Sprintf("%d.0", major)
} else {
major = utils.MustParseInt(arr[0])
minor = utils.MustParseInt(arr[1])
version = fmt.Sprintf("%s.%s", arr[0], arr[1])
downgradeVersion = fmt.Sprintf("%d.%d", major, minor-1)
version = fmt.Sprintf("%d.%d", major, minor)
}

// Newest system lack DeveloperDiskImage, try fallback to last minor version
if minor > 0 {
FallbackVersion = fmt.Sprintf("%d.%d", major, minor-1)
}

return &UsbmuxdImage{
Device: device,
ImageMounted: false,
DeveloperDiskImageUrl: strings.Replace(imageSource, "{0}", version, -1),
DeveloperDiskImageVersion: version,
DowngradeDeveloperDiskImageUrl: strings.Replace(imageSource, "{0}", downgradeVersion, -1),
DowngradeDeveloperDiskImageVersion: downgradeVersion,
Device: device,
ImageMounted: false,
DeveloperDiskImageUrl: strings.Replace(imageSource, "{0}", version, -1),
DeveloperDiskImageVersion: version,
DeveloperDiskImageFallbackUrl: strings.Replace(imageSource, "{0}", FallbackVersion, -1),
DeveloperDiskImageFallbackVersion: FallbackVersion,
}
}
117 changes: 57 additions & 60 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/bitxeno/atvloadly/internal/cfg"
"github.com/bitxeno/atvloadly/internal/http"
"github.com/bitxeno/atvloadly/internal/log"
"github.com/bitxeno/atvloadly/internal/utils"
"github.com/bitxeno/atvloadly/manager"
"github.com/bitxeno/atvloadly/model"
"github.com/shirou/gopsutil/v3/process"
Expand Down Expand Up @@ -80,95 +81,91 @@ func MountDeveloperDiskImage(ctx context.Context, id string) error {
return err
}

// 已挂载直接返回
// Already mounted, return directly.
if imageInfo.ImageMounted {
return nil
}

// 尝试挂载
// 对应版本的DeveloperDiskImage不存在的话,尝试下载
// Download DeveloperDiskImage
imageVersionDir := filepath.Join(cfg.Server.WorkDir, "DeveloperDiskImage", imageInfo.DeveloperDiskImageVersion)
dmg := filepath.Join(imageVersionDir, "DeveloperDiskImage.dmg")
signature := filepath.Join(imageVersionDir, "DeveloperDiskImage.dmg.signature")

if _, err := os.Stat(dmg); os.IsNotExist(err) {
if err := downloadDeveloperDiskImage(imageInfo, imageVersionDir); err != nil {
log.Err(err).Msg("Download Developer disk image error: ")
return err
}
fallback, err := downloadDeveloperDiskImage(imageInfo)
if err != nil {
log.Err(err).Msg("Download Developer disk image error: ")
return err
}
if fallback {
imageVersionDir = filepath.Join(cfg.Server.WorkDir, "DeveloperDiskImage", imageInfo.DeveloperDiskImageFallbackVersion)
dmg = filepath.Join(imageVersionDir, "DeveloperDiskImage.dmg")
signature = filepath.Join(imageVersionDir, "DeveloperDiskImage.dmg.signature")
}

// 开始执行挂载
// Start executing mounting DeveloperDiskImage
cmd := exec.CommandContext(ctx, "ideviceimagemounter", "-u", device.UDID, "-n", dmg, signature)
data, err := cmd.CombinedOutput()
if err != nil {
log.Err(err).Msg("Run ideviceimagemounter error: ")
log.Err(err).Msgf("Run ideviceimagemounter error: %s", string(data))
return fmt.Errorf("%s%s", string(data), err.Error())
}

output := string(data)
if strings.Contains(output, "ERROR") {
return fmt.Errorf("%s\n%s", "Run ideviceimagemounter error: ", output)
return nil
}

func downloadDeveloperDiskImage(imageInfo *model.UsbmuxdImage) (fallback bool, reterr error) {
// download current version DeveloperDiskImage
err := downloadDeveloperDiskImageByVersion(imageInfo.DeveloperDiskImageUrl, imageInfo.DeveloperDiskImageVersion)
if err != nil && imageInfo.DeveloperDiskImageFallbackVersion != "" {
log.Warnf("try downgrade developer disk image to version: %s", imageInfo.DeveloperDiskImageFallbackVersion)
// current version DeveloperDiskImage not exist, fallback to last minor version
reterr = downloadDeveloperDiskImageByVersion(imageInfo.DeveloperDiskImageFallbackUrl, imageInfo.DeveloperDiskImageFallbackVersion)
fallback = true
return
}

if err != nil {
log.Err(err).Msg("Download developer disk image error: ")
reterr = err
}

return nil
return
}

func downloadDeveloperDiskImage(imageInfo *model.UsbmuxdImage, imageVersionDir string) error {
func downloadDeveloperDiskImageByVersion(url string, version string) error {
imageVersionDir := filepath.Join(cfg.Server.WorkDir, "DeveloperDiskImage", version)
dmg := filepath.Join(imageVersionDir, "DeveloperDiskImage.dmg")
signature := filepath.Join(imageVersionDir, "DeveloperDiskImage.dmg.signature")
if utils.Exists(dmg) && utils.Exists(signature) {
return nil
}

tmpPath := filepath.Join(cfg.Server.WorkDir, "tmp", "DeveloperDiskImage.zip")
tmpUnzipPath := filepath.Join(cfg.Server.WorkDir, "tmp", "DeveloperDiskImage")
_ = os.RemoveAll(tmpUnzipPath)

resp, err := http.NewClient().R().SetOutput(tmpPath).Get(imageInfo.DeveloperDiskImageUrl)
if err == nil && resp.IsSuccess() {
// unzip
uz := unzip.New()
files, err := uz.Extract(tmpPath, tmpUnzipPath)
if err != nil {
log.Err(err).Msg("Unzip Developer disk image error: ")
return err
}
_ = os.MkdirAll(imageVersionDir, os.ModePerm)
for _, f := range files {
if filepath.Base(f) == "DeveloperDiskImage.dmg" || filepath.Base(f) == "DeveloperDiskImage.dmg.signature" {
if err = os.Rename(filepath.Join(tmpUnzipPath, f), filepath.Join(imageVersionDir, filepath.Base(f))); err != nil {
return err
}
}
}
return nil
// download current version DeveloperDiskImage
resp, err := http.NewClient().R().SetOutput(tmpPath).Get(url)
if err != nil {
return err
}

// 镜像找不到,尝试降级获取上一版本(有时可以使用前一版本的镜像进行mount)
if resp.StatusCode() == 404 {
log.Warnf("try downgrade Developer disk image to version: %s", imageInfo.DowngradeDeveloperDiskImageVersion)
resp, err = http.NewClient().R().SetOutput(tmpPath).Get(imageInfo.DowngradeDeveloperDiskImageUrl)
if err == nil && resp.IsSuccess() {
// unzip
uz := unzip.New()
files, err := uz.Extract(tmpPath, tmpUnzipPath)
if err != nil {
log.Err(err).Msg("Unzip Developer disk image error: ")
return err
}
_ = os.MkdirAll(imageVersionDir, os.ModePerm)
for _, f := range files {
if filepath.Base(f) == "DeveloperDiskImage.dmg" || filepath.Base(f) == "DeveloperDiskImage.dmg.signature" {
if err = os.Rename(filepath.Join(tmpUnzipPath, f), filepath.Join(imageVersionDir, filepath.Base(f))); err != nil {
return err
}
}
}
return nil
}
if !resp.IsSuccess() {
return fmt.Errorf("Developer disk image download failed. url: %s status: %d", url, resp.StatusCode())
}

// unzip
uz := unzip.New()
files, err := uz.Extract(tmpPath, tmpUnzipPath)
if err != nil {
log.Err(err).Msg("Download Developer disk image error: ")
log.Err(err).Msg("Unzip Developer disk image error: ")
return err
}
if !resp.IsSuccess() {
return fmt.Errorf("Developer disk image could not found. os: tvOS %s url: %s status: %d", imageInfo.Device.ProductVersion, imageInfo.DeveloperDiskImageUrl, resp.StatusCode())
_ = os.MkdirAll(imageVersionDir, os.ModePerm)
for _, f := range files {
if filepath.Base(f) == "DeveloperDiskImage.dmg" || filepath.Base(f) == "DeveloperDiskImage.dmg.signature" {
if err = os.Rename(filepath.Join(tmpUnzipPath, f), filepath.Join(imageVersionDir, filepath.Base(f))); err != nil {
return err
}
}
}

return nil
Expand Down

0 comments on commit fa392aa

Please sign in to comment.