提交 13422787 编写于 作者: P peterq

add: 下载状态同步到qml层

上级 56e6abdf
......@@ -34,3 +34,7 @@ func DoClose() {
}
closeCb = nil
}
var NotifyQml = func(event string, data map[string]interface{}) {
log.Println("not ready")
}
......@@ -54,16 +54,13 @@ type Task struct {
fileLength int64 // 文件总大小
undistributed []*segment // 尚未分配的片段
wroteToDisk []*segment // 文件内容写入磁盘的情况
distributeLock sync.Mutex
undistributedLock sync.Mutex
distributedLock sync.Mutex
finishedLock sync.Mutex
wroteToDiskLock sync.Mutex
lastCaptureTime time.Time // 上次快照时间
workers map[int]*worker // 工作协程map
workersLock sync.Mutex
fileHandle *os.File
fileLock sync.Mutex
cancelSpeedCoroutine context.CancelFunc
speedCoroutineContext context.Context
}
......@@ -183,8 +180,6 @@ func (task *Task) start() (err error) {
func (task *Task) distributeSegment() (seg *segment, err error) {
task.undistributedLock.Lock()
defer task.undistributedLock.Unlock()
task.distributedLock.Lock()
defer task.distributedLock.Unlock()
segLen := len(task.undistributed)
if segLen == 0 {
return nil, noMoreSeg
......@@ -210,8 +205,8 @@ func (task *Task) distributeSegment() (seg *segment, err error) {
// 写入数据到磁盘
func (task *Task) writeToDisk(from int64, buffer *bytes.Buffer) (err error) {
task.fileLock.Lock()
defer task.fileLock.Unlock()
task.wroteToDiskLock.Lock()
defer task.wroteToDiskLock.Unlock()
_, err = task.fileHandle.Seek(from, io.SeekStart)
if err != nil {
return errors.Wrap(err, "文件seek错误")
......@@ -221,16 +216,40 @@ func (task *Task) writeToDisk(from int64, buffer *bytes.Buffer) (err error) {
if err != nil {
return errors.Wrap(err, "文件写入错误")
}
task.wroteToDiskLock.Lock()
defer task.wroteToDiskLock.Unlock()
putBackSegment(task.wroteToDisk, &segment{
start: from,
len: l,
finish: l,
})
task.capture()
return
}
func (task *Task) capture() {
if time.Now().Sub(task.lastCaptureTime) < time.Second {
return
}
task.lastCaptureTime = time.Now()
c := &internal.TaskCapture{
Fid: string(task.id),
SavePath: task.savePath,
Completed: []*internal.FinishSeg{},
Length: task.fileLength,
}
for _, seg := range task.wroteToDisk {
c.Completed = append(c.Completed, &internal.FinishSeg{
Start: seg.start,
Len: seg.len,
})
}
bin, err := proto.Marshal(c)
if err != nil {
log.Println("快照编码错误", err)
return
}
task.notifyEvent("capture", string(bin))
}
// 下载出错, 放回片段到未下载
func (task *Task) downloadSegmentError(seg *segment) {
task.undistributedLock.Lock()
......@@ -252,10 +271,6 @@ func logErr(strContent string) {
// 下载成功, 放回片段到已下载
func (task *Task) downloadSegmentSuccess(seg *segment) {
task.distributedLock.Lock()
defer task.distributedLock.Unlock()
task.finishedLock.Lock()
defer task.finishedLock.Unlock()
if seg.len == seg.finish {
return
}
......@@ -264,6 +279,8 @@ func (task *Task) downloadSegmentSuccess(seg *segment) {
len: seg.len - seg.finish,
finish: 0,
}
task.undistributedLock.Lock()
defer task.undistributedLock.Unlock()
task.undistributed = putBackSegment(task.undistributed, seg2)
}
......@@ -272,7 +289,7 @@ func (task *Task) onWorkerExit(w *worker) {
task.workersLock.Lock()
defer task.workersLock.Unlock()
delete(task.workers, w.id)
log.Println(fmt.Sprintf("task %d, worker %d exit", task.id, w.id))
log.Println(fmt.Sprintf("task %s, worker %d exit", task.id, w.id))
if len(task.workers) == 0 {
go task.onAllWorkerExit()
}
......
......@@ -106,17 +106,10 @@ ReadStream:
case <-w.ctx.Done():
bufLen := int64(buf.Len())
if bufLen > 0 {
writeErr := w.task.writeToDisk(seg.start+seg.finish, buf)
if writeErr != nil {
err = writeErr
break ReadStream
}
seg.finish += bufLen
seg.start += seg.finish
seg.len -= seg.finish
seg.finish = 0
err = w.task.writeToDisk(seg.start+seg.finish, buf)
} else {
err = errors.New("canceled")
}
err = errors.New("canceled")
break ReadStream
}
if l > 0 { // 有数据, 写入缓存
......
......@@ -2,6 +2,15 @@
package functions
import (
"github.com/peterq/pan-light/pc/dep"
"log"
)
func init() {
dep.NotifyQml = NotifyQml
}
type syncHandler func(p map[string]interface{}) interface{}
type asyncHandler func(p map[string]interface{}, resolve func(interface{}),
......@@ -43,3 +52,7 @@ func RegisterSync(register func(routes map[string]func(map[string]interface{}) i
register(r1)
}
}
var NotifyQml = func(event string, data map[string]interface{}) {
log.Println("this function should be load from plugin", event, data)
}
......@@ -2,7 +2,14 @@
package functions
import "github.com/peterq/pan-light/pc/gui/bridge"
import (
"github.com/peterq/pan-light/pc/dep"
"github.com/peterq/pan-light/pc/gui/bridge"
)
func init() {
dep.NotifyQml = NotifyQml
}
type syncHandler func(p map[string]interface{}) (result interface{})
......@@ -25,3 +32,7 @@ func asyncMap(r map[string]asyncHandler) {
}
bridge.AsyncRouteRegister(r1)
}
func NotifyQml(event string, data map[string]interface{}) {
bridge.NotifyQml(event, data)
}
......@@ -36,3 +36,7 @@ func AsyncRouteRegister(routes map[string]func(map[string]interface{},
func(interface{}), func(interface{}), func(interface{}), chan interface{})) {
bridge.AsyncRouteRegister(routes)
}
func NotifyQml(event string, data map[string]interface{}) {
bridge.NotifyQml(event, data)
}
......@@ -395,26 +395,12 @@ function listModelMove(model, from, to) {
return listModelToArr(model)
}
function humanSize(size) {
var i, unit = ['B', 'KB', 'MB', 'GB']
for (i = 0; i < unit.length - 1; i++) {
if (size < 1024)
break
size /= 1024
}
return size.toFixed(2) + unit[i]
}
......@@ -11,11 +11,14 @@ Item {
property bool isFinish
property string downloadId: meta.downloadId
property var meta
property int idx
property string resumeData: ''
property bool isNewAdd: true
signal taskEvent(string event, var data)
property string speed: ''
Component.onCompleted: {
if (!isNewAdd) {
console.log('恢复任务', downloadId)
......@@ -26,6 +29,21 @@ Item {
}
}
Timer {
id: speedClearTimer
interval: 2000
onTriggered: {
speed = ''
}
}
onTaskEvent: {
if (event === 'task.speed') {
speed = Util.humanSize(data) + '/s'
speedClearTimer.restart()
}
}
DataSaver {
$key: 'download-item-' + root.downloadId
property alias resumeData: root.resumeData
......@@ -45,15 +63,21 @@ Item {
type: root.meta.saveName.split('.').pop()
}
Text {
id: fileNameText
text: root.meta.saveName
anchors.verticalCenter: parent.verticalCenter
anchors.left: fileIcon.right
anchors.leftMargin: 5
anchors.right: parent.right
anchors.rightMargin: 5
width: parent.width * 0.5
elide: Text.ElideRight
}
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.left: fileNameText.right
text: speed
}
MouseArea {
hoverEnabled: true
anchors.fill: parent
......
......@@ -22,6 +22,7 @@ Rectangle {
id: item
meta: listModel.get(index)
isFinish: root.isFinish
idx: index
Connections {
target: root
onCheckFid: {
......@@ -42,6 +43,19 @@ Rectangle {
Component.onCompleted: {
Util.arrToListModel(list(), listModel)
// updateList(Util.listModelClear(listModel))
if (!isFinish) {
Util.event.on('go.task.event', function(evt) {
var id = evt.taskId
for (var i = 0; i < listModel.count; i++) {
if (listModel.get(i).downloadId === id) {
listView.currentIndex = i
listView.currentItem.taskEvent(evt.type, evt.data)
return
}
}
console.log('-------- task id not found', JSON.stringify(evt))
})
}
}
function list() {
......
......@@ -46,8 +46,13 @@ func handleDownloadEvent(event *downloader.DownloadEvent) {
speed := float64(event.Data.(int64))
log.Println(speed / 1024 / 1024)
} else {
log.Println(event)
//log.Println(event)
}
dep.NotifyQml("task.event", map[string]interface{}{
"type": event.Event,
"taskId": event.TaskId,
"data": event.Data,
})
}
func test() {
......
......@@ -31,11 +31,17 @@ func main() {
if err != nil {
panic(err)
}
NotifyQml, err := p.Lookup("NotifyQml")
if err != nil {
panic(err)
}
functions.RegisterAsync(AsyncRouteRegister.(func(routes map[string]func(map[string]interface{},
func(interface{}), func(interface{}), func(interface{}), chan interface{}))))
functions.RegisterSync(SyncRouteRegister.(func(routes map[string]func(map[string]interface{}) interface{})))
functions.NotifyQml = NotifyQml.(func(event string, data map[string]interface{}))
dep.NotifyQml = functions.NotifyQml
StartGui.(func(rccFile, mainQml string))("./gui/qml/qml.rcc", "qrc:/main.qml")
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册