Compare commits
	
		
			4 Commits
		
	
	
		
			06d860c601
			...
			v0.3.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 7a08f7cbe2 | ||
|   | dd37238510 | ||
|   | c8d5f335b1 | ||
|   | bb80b3ee54 | 
							
								
								
									
										13
									
								
								cista/api.py
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								cista/api.py
									
									
									
									
									
								
							| @@ -37,16 +37,23 @@ async def upload(req, ws): | ||||
|             ) | ||||
|         req = msgspec.json.decode(text, type=FileRange) | ||||
|         pos = req.start | ||||
|         data = None | ||||
|         while pos < req.end and (data := await ws.recv()) and isinstance(data, bytes): | ||||
|         while True: | ||||
|             data = await ws.recv() | ||||
|             if not isinstance(data, bytes): | ||||
|                 break | ||||
|             if len(data) > req.end - pos: | ||||
|                 raise ValueError( | ||||
|                     f"Expected up to {req.end - pos} bytes, got {len(data)} bytes" | ||||
|                 ) | ||||
|             sentsize = await alink(("upload", req.name, pos, data, req.size)) | ||||
|             pos += typing.cast(int, sentsize) | ||||
|             if pos >= req.end: | ||||
|                 break | ||||
|         if pos != req.end: | ||||
|             d = f"{len(data)} bytes" if isinstance(data, bytes) else data | ||||
|             raise ValueError(f"Expected {req.end - pos} more bytes, got {d}") | ||||
|         # Report success | ||||
|         res = StatusMsg(status="ack", req=req) | ||||
|         print("ack", res) | ||||
|         await asend(ws, res) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -34,9 +34,11 @@ class File: | ||||
|             self.open_rw() | ||||
|         assert self.fd is not None | ||||
|         if file_size is not None: | ||||
|             assert pos + len(buffer) <= file_size | ||||
|             os.ftruncate(self.fd, file_size) | ||||
|         os.lseek(self.fd, pos, os.SEEK_SET) | ||||
|         os.write(self.fd, buffer) | ||||
|         if buffer: | ||||
|             os.lseek(self.fd, pos, os.SEEK_SET) | ||||
|             os.write(self.fd, buffer) | ||||
|  | ||||
|     def __getitem__(self, slice): | ||||
|         if self.fd is None: | ||||
|   | ||||
| @@ -234,7 +234,7 @@ let modifiedTimer: any = null | ||||
| const updateModified = () => { | ||||
|   for (const doc of props.documents) doc.modified = formatUnixDate(doc.mtime) | ||||
| } | ||||
| onMounted(() => { modifiedTimer = setInterval(updateModified, 1000) }) | ||||
| onMounted(() => { updateModified(); modifiedTimer = setInterval(updateModified, 1000) }) | ||||
| onUnmounted(() => { clearInterval(modifiedTimer) }) | ||||
| const mkdir = (doc: Document, name: string) => { | ||||
|   const control = connect(controlUrl, { | ||||
|   | ||||
| @@ -16,13 +16,51 @@ type CloudFile = { | ||||
|   cloudName: string | ||||
|   cloudPos: number | ||||
| } | ||||
|  | ||||
| function pasteHandler(event: ClipboardEvent) { | ||||
|   const items = Array.from(event.clipboardData?.items ?? []) | ||||
|   const infiles = [] as File[] | ||||
|   const dirs = [] as FileSystemDirectoryEntry[] | ||||
|   for (const item of items) { | ||||
|     if (item.kind !== 'file') continue | ||||
|     const entry = item.webkitGetAsEntry() | ||||
|     if (entry?.isFile) { | ||||
|       const file = item.getAsFile() | ||||
|       infiles.push(file) | ||||
|     } else if (entry?.isDirectory) { | ||||
|       dirs.push(entry as FileSystemDirectoryEntry) | ||||
|     } | ||||
|   } | ||||
|   if (infiles.length || dirs.length) { | ||||
|     event.preventDefault() | ||||
|     uploadFiles(infiles) | ||||
|     for (const entry of dirs) pasteDirectory(entry, `${props.path!.join('/')}/${entry.name}`) | ||||
|   } | ||||
| } | ||||
| const pasteDirectory = async (entry: FileSystemDirectoryEntry, loc: string) => { | ||||
|   const reader = entry.createReader() | ||||
|   const entries = await new Promise<any[]>(resolve => reader.readEntries(resolve)) | ||||
|   const cloudfiles = [] as CloudFile[] | ||||
|   for (const entry of entries) { | ||||
|     const cloudName = `${loc}/${entry.name}` | ||||
|     if (entry.isFile) { | ||||
|       const file = await new Promise(resolve => entry.file(resolve)) as File | ||||
|       cloudfiles.push({file, cloudName, cloudPos: 0}) | ||||
|     } else if (entry.isDirectory) { | ||||
|       await pasteDirectory(entry, cloudName) | ||||
|     } | ||||
|   } | ||||
|   if (cloudfiles.length) uploadCloudFiles(cloudfiles) | ||||
| } | ||||
| function uploadHandler(event: Event) { | ||||
|   event.preventDefault() | ||||
|   event.stopPropagation() | ||||
|   // @ts-ignore | ||||
|   const infiles = Array.from(event.dataTransfer?.files || event.target.files) as File[] | ||||
|   if (!infiles.length) return | ||||
|   const input = event.target as HTMLInputElement | null | ||||
|   const infiles = Array.from((input ?? (event as DragEvent).dataTransfer)?.files ?? []) as File[] | ||||
|   if (input) input.value = '' | ||||
|   if (infiles.length) uploadFiles(infiles) | ||||
| } | ||||
|  | ||||
| const uploadFiles = (infiles: File[]) => { | ||||
|   const loc = props.path!.join('/') | ||||
|   let files = [] | ||||
|   for (const file of infiles) { | ||||
| @@ -32,6 +70,9 @@ function uploadHandler(event: Event) { | ||||
|       cloudPos: 0, | ||||
|     }) | ||||
|   } | ||||
|   uploadCloudFiles(files) | ||||
| } | ||||
| const uploadCloudFiles = (files: CloudFile[]) => { | ||||
|   const dotfiles = files.filter(f => f.cloudName.includes('/.')) | ||||
|   if (dotfiles.length) { | ||||
|     documentStore.error = "Won't upload dotfiles" | ||||
| @@ -165,10 +206,6 @@ const worker = async () => { | ||||
|   const ws = await WSCreate() | ||||
|   while (upqueue.length) { | ||||
|     const f = upqueue[0] | ||||
|     if (f.cloudPos === f.file.size) { | ||||
|       upqueue.shift() | ||||
|       continue | ||||
|     } | ||||
|     const start = f.cloudPos | ||||
|     const end = Math.min(f.file.size, start + (1<<20)) | ||||
|     const control = { name: f.cloudName, size: f.file.size, start, end } | ||||
| @@ -179,6 +216,7 @@ const worker = async () => { | ||||
|     ws.sendMsg(control) | ||||
|     // @ts-ignore | ||||
|     await ws.sendData(data) | ||||
|     if (f.cloudPos === f.file.size) upqueue.shift() | ||||
|   } | ||||
|   if (upqueue.length) startWorker() | ||||
|   uprogress.status = "idle" | ||||
| @@ -196,8 +234,10 @@ onMounted(() => { | ||||
|   // Need to prevent both to prevent browser from opening the file | ||||
|   addEventListener('dragover', uploadHandler) | ||||
|   addEventListener('drop', uploadHandler) | ||||
|   addEventListener('paste', pasteHandler) | ||||
| }) | ||||
| onUnmounted(() => { | ||||
|   removeEventListener('paste', pasteHandler) | ||||
|   removeEventListener('dragover', uploadHandler) | ||||
|   removeEventListener('drop', uploadHandler) | ||||
| }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user