github.com/0chain/gosdk@v1.17.11/wasmsdk/player_file.go (about)

     1  //go:build js && wasm
     2  // +build js,wasm
     3  
     4  package main
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  
    10  	"github.com/0chain/gosdk/zboxcore/marker"
    11  	"github.com/0chain/gosdk/zboxcore/sdk"
    12  )
    13  
    14  type FilePlayer struct {
    15  	allocationID string
    16  	remotePath   string
    17  	authTicket   string
    18  	lookupHash   string
    19  	numBlocks    int
    20  
    21  	isViewer      bool
    22  	allocationObj *sdk.Allocation
    23  	authTicketObj *marker.AuthTicket
    24  	playlistFile  *sdk.PlaylistFile
    25  
    26  	downloadedChunks chan []byte
    27  	downloadedLen    int
    28  	ctx              context.Context
    29  	cancel           context.CancelFunc
    30  	prefetchQty      int
    31  }
    32  
    33  func (p *FilePlayer) Start() error {
    34  	if p.cancel != nil {
    35  		p.cancel()
    36  	}
    37  
    38  	p.ctx, p.cancel = context.WithCancel(context.TODO())
    39  
    40  	file, err := p.loadPlaylistFile()
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	p.playlistFile = file
    46  
    47  	p.downloadedChunks = make(chan []byte, p.prefetchQty)
    48  
    49  	go p.startDownload()
    50  
    51  	return nil
    52  }
    53  
    54  func (p *FilePlayer) Stop() {
    55  	if p.cancel != nil {
    56  		p.cancel()
    57  		p.cancel = nil
    58  	}
    59  }
    60  
    61  func (p *FilePlayer) download(startBlock int64) {
    62  	endBlock := startBlock + int64(p.numBlocks) - 1
    63  
    64  	if endBlock > p.playlistFile.NumBlocks {
    65  		endBlock = p.playlistFile.NumBlocks
    66  	}
    67  	fmt.Println("start:", startBlock, "end:", endBlock, "numBlocks:", p.numBlocks, "total:", p.playlistFile.NumBlocks)
    68  
    69  	data, err := downloadBlocks(p.allocationObj.ID, p.remotePath, p.authTicket, p.lookupHash, startBlock, endBlock)
    70  	// data, err := downloadBlocks2(int(startBlock), int(endBlock), p.allocationObj, p.remotePath)
    71  	if err != nil {
    72  		PrintError(err.Error())
    73  		return
    74  	}
    75  	withRecover(func() {
    76  		if p.downloadedChunks != nil {
    77  			p.downloadedChunks <- data
    78  		}
    79  	})
    80  }
    81  
    82  func (p *FilePlayer) startDownload() {
    83  	fmt.Println("start download")
    84  	if p.playlistFile.NumBlocks < 1 {
    85  		PrintError("playlist: numBlocks is invalid")
    86  		return
    87  	}
    88  	var startBlock int64 = 1
    89  	for {
    90  		select {
    91  		case <-p.ctx.Done():
    92  			PrintInfo("playlist: download is cancelled")
    93  			return
    94  		default:
    95  			fmt.Println("download start:", startBlock)
    96  			p.download(startBlock)
    97  
    98  			startBlock += int64(p.numBlocks)
    99  			fmt.Println("download end, new start:", startBlock)
   100  
   101  			if startBlock > p.playlistFile.NumBlocks {
   102  
   103  				go func() {
   104  					// trigger js to close stream
   105  					p.downloadedChunks <- nil
   106  				}()
   107  				return
   108  			}
   109  
   110  		}
   111  	}
   112  
   113  }
   114  
   115  func (p *FilePlayer) loadPlaylistFile() (*sdk.PlaylistFile, error) {
   116  	if p.isViewer {
   117  		//get playlist file from auth ticket
   118  		return sdk.GetPlaylistFileByAuthTicket(p.ctx, p.allocationObj, p.authTicket, p.lookupHash)
   119  	}
   120  
   121  	d, err := p.allocationObj.ListDir(p.remotePath)
   122  	if err != nil {
   123  		fmt.Println("could not list dir:", p.remotePath)
   124  		return nil, err
   125  	}
   126  	f := d.Children[0]
   127  	var (
   128  		dataShards            = p.allocationObj.DataShards
   129  		effectivePerShardSize = (int(f.ActualSize) + dataShards - 1) / dataShards
   130  		totalBlocks           = (effectivePerShardSize + sdk.DefaultChunkSize - 1) / sdk.DefaultChunkSize
   131  	)
   132  
   133  	fmt.Println("totalBlocks:", totalBlocks)
   134  	fmt.Println("file size:", f.Size)
   135  
   136  	return &sdk.PlaylistFile{
   137  		Name:           f.Name,
   138  		Path:           f.Path,
   139  		LookupHash:     f.LookupHash,
   140  		NumBlocks:      int64(totalBlocks),
   141  		Size:           f.Size,
   142  		ActualFileSize: f.ActualSize,
   143  		MimeType:       f.MimeType,
   144  		Type:           f.Type,
   145  	}, nil
   146  }
   147  
   148  func (p *FilePlayer) GetNext() []byte {
   149  	b, ok := <-p.downloadedChunks
   150  	if ok {
   151  		if p.downloadedLen+len(b) > int(p.playlistFile.ActualFileSize) {
   152  			b = b[:int(p.playlistFile.ActualFileSize)-p.downloadedLen]
   153  		}
   154  		p.downloadedLen += len(b)
   155  		return b
   156  	}
   157  
   158  	return nil
   159  }
   160  
   161  // createFilePalyer create player for remotePath
   162  func createFilePalyer(allocationID, remotePath, authTicket, lookupHash string) (*FilePlayer, error) {
   163  	player := &FilePlayer{}
   164  	player.prefetchQty = 3
   165  	player.remotePath = remotePath
   166  	player.authTicket = authTicket
   167  	player.lookupHash = lookupHash
   168  	player.numBlocks = 10
   169  	player.allocationID = allocationID
   170  
   171  	//player is viewer
   172  	if len(authTicket) > 0 {
   173  		//player is viewer via shared authticket
   174  		at, err := sdk.InitAuthTicket(authTicket).Unmarshall()
   175  
   176  		if err != nil {
   177  			PrintError(err)
   178  			return nil, err
   179  		}
   180  
   181  		allocationObj, err := sdk.GetAllocationFromAuthTicket(authTicket)
   182  		if err != nil {
   183  			PrintError("Error fetching the allocation", err)
   184  			return nil, err
   185  		}
   186  
   187  		player.isViewer = true
   188  		player.allocationObj = allocationObj
   189  		player.authTicketObj = at
   190  		player.lookupHash = at.FilePathHash
   191  
   192  		return player, nil
   193  
   194  	}
   195  
   196  	if len(allocationID) == 0 {
   197  		return nil, RequiredArg("allocationID")
   198  	}
   199  
   200  	allocationObj, err := sdk.GetAllocation(allocationID)
   201  	if err != nil {
   202  		PrintError("Error fetching the allocation", err)
   203  		return nil, err
   204  	}
   205  
   206  	player.isViewer = false
   207  	player.allocationObj = allocationObj
   208  
   209  	return player, nil
   210  }