about summary refs log blame commit diff stats
path: root/src/types/blob.nim
blob: dd812c0268c9e5908ecb05f76a7fc3d3c3f93918 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                  
                
                   
 
                
                    
                 
                      

    
                                             

                               



                                    
                           


                                        
                           
 


                     
                                                        








                                     

                              
                                                   
                     


                                        


                                                         
                 


                                              

   







                                             
                                                                        
                                                      
                     
                  



                           


                                            






                                                                


                                        
                   
                                    

             

                             
                                   




                                       
                  
 


                                              


                                     

                                                            
import std/options
import std/posix
import std/strutils

import js/fromjs
import js/javascript
import js/jstypes
import utils/mimeguess

type
  DeallocFun = proc() {.closure, raises: [].}

  Blob* = ref object of RootObj
    size* {.jsget.}: uint64
    ctype* {.jsget: "type".}: string
    buffer*: pointer
    deallocFun*: DeallocFun
    fd*: Option[FileHandle]

  WebFile* = ref object of Blob
    webkitRelativePath {.jsget.}: string
    name* {.jsget.}: string

jsDestructor(Blob)
jsDestructor(WebFile)

proc newBlob*(buffer: pointer; size: int; ctype: string;
    deallocFun: DeallocFun): Blob =
  return Blob(
    buffer: buffer,
    size: uint64(size),
    ctype: ctype,
    deallocFun: deallocFun
  )

proc finalize(blob: Blob) {.jsfin.} =
  if blob.fd.isSome:
    discard close(blob.fd.get)
  if blob.deallocFun != nil and blob.buffer != nil:
    blob.deallocFun()
    blob.buffer = nil

proc finalize(file: WebFile) {.jsfin.} =
  Blob(file).finalize()

proc newWebFile*(name: string; fd: FileHandle): WebFile =
  return WebFile(
    name: name,
    fd: some(fd),
    ctype: DefaultGuess.guessContentType(name)
  )

type
  BlobPropertyBag = object of JSDict
    `type`: string
    #TODO endings

  FilePropertyBag = object of BlobPropertyBag
    #TODO lastModified: int64

proc newWebFile(ctx: JSContext; fileBits: seq[string]; fileName: string;
    options = FilePropertyBag()): WebFile {.jsctor.} =
  let file = WebFile(
    name: fileName
  )
  var len = 0
  for blobPart in fileBits:
    len += blobPart.len
  let buffer = alloc(len)
  file.buffer = buffer
  file.deallocFun = proc() = dealloc(buffer)
  var buf = cast[ptr UncheckedArray[uint8]](file.buffer)
  var i = 0
  for blobPart in fileBits:
    if blobPart.len > 0:
      copyMem(addr buf[i], unsafeAddr blobPart[0], blobPart.len)
      i += blobPart.len
  file.size = uint64(len)
  block ctype:
    for c in options.`type`:
      if c notin char(0x20)..char(0x7E):
        break ctype
      file.ctype &= c.toLowerAscii()
  return file

#TODO File, Blob constructors

proc getSize*(this: Blob): uint64 =
  if this.fd.isSome:
    var statbuf: Stat
    if fstat(this.fd.get, statbuf) < 0:
      return 0
    return uint64(statbuf.st_size)
  return this.size

proc size*(this: WebFile): uint64 {.jsfget.} =
  return this.getSize()

#TODO lastModified

proc addBlobModule*(ctx: JSContext) =
  let blobCID = ctx.registerType(Blob)
  ctx.registerType(WebFile, parent = blobCID, name = "File")