Skip to content

Commit

Permalink
Experiment with setting md5hash to None while uploading to Jottacloud…
Browse files Browse the repository at this point in the history
…, as per #99 and #100.
  • Loading branch information
havardgulldahl committed Jun 20, 2016
1 parent 62ba0cb commit 1b7e188
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 12 deletions.
33 changes: 21 additions & 12 deletions src/jottalib/JFS.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,13 @@ def write(self, data):
self.jfs.up(self.path, data)

def writepartial(self, data, offset):
return NotImplementedError
#raise NotImplementedError
# TODO: figure out whether adding data to an existing file actually works
# It seems like the API only supports resuming previous uploads, not arbitrary additions
md5hash = hashlib.md5(data).hexdigest()
url = self.path.replace('www.jotta.no', 'up.jottacloud.com')
now = datetime.datetime.now().isoformat()
headers = {'JMd5':md5hash,
headers = {#'JMd5':md5hash,
'JCreated': now,
'JModified': now,
'X-Jfs-DeviceName': 'Jotta',
Expand All @@ -249,8 +249,8 @@ def writepartial(self, data, offset):
# TODO: fix the computation of the denominator above. It seems it should be
# the total length of data + content-transfer envelope
}
params = {'cphash':md5hash,}
files = {'md5': ('', md5hash),
params = {}#'cphash':md5hash,}
files = {#'md5': ('', md5hash),
'modified': ('', now),
'created': ('', now),
'file': (self.name, data, 'application/octet-stream', {'Content-Transfer-Encoding':'binary'})}
Expand Down Expand Up @@ -648,25 +648,32 @@ def up(self, path, fileobject, resume=False):
md5.update(chunk)
contentsize += len(chunk)
md5hash = md5.hexdigest()
contentsize = contentsize*1000
fileobject.seek(0) # rewind read head
url = path.replace('www.jotta.no', 'up.jottacloud.com')
now = datetime.datetime.now().isoformat()
headers = {'JMd5':md5hash,
headers = {#'JMd5':md5hash,
'JCreated': now,
'JModified': now,
'X-Jfs-DeviceName': 'Jotta',
'JSize': contentsize,
'jx_csid': '',
'jx_lisence': ''
}
params = {'cphash':md5hash,}
params = {}#'cphash':md5hash,}
partialchunksize = 1024*1024*5#*512
#TODO: check if file is incomplete, and continue, if resume=True
offset=0
if resume is False:
offset=0
else:
#figure out existing file size
y = self.getObject(path)
offset = y.size

for i, chunk in enumerate(iter(lambda: fileobject.read(partialchunksize), b'')): #loop thru content
chunksize = len(chunk)
logging.debug('posting chunk %s (len %s, offset %s, hash %s)', i, chunksize, offset, md5hash)
files = {'md5': ('', md5hash),
files = {#'md5': ('', md5hash),
'modified': ('', now),
'created': ('', now),
'file': (os.path.basename(url), chunk, 'application/octet-stream', {'Content-Transfer-Encoding':'binary'})}
Expand Down Expand Up @@ -722,7 +729,7 @@ def usage(self):
import netrc
try:
n = netrc.netrc()
username, account, password = n.authenticators('jottacloud') # read .netrc entry for 'machine jottacloud'
username, account, password = n.authenticators('jottacloud.com') # read .netrc entry for 'machine jottacloud'
except Exception as e:
logging.exception(e)
username = os.environ['JOTTACLOUD_USERNAME']
Expand All @@ -740,8 +747,10 @@ def usage(self):
# except IndexError:
# _filename = '/tmp/test.pdf'
# r = jottasync.up(_filename)
f = jfs.up('/Jotta/Sync/runtest.txt', StringIO('12345'))
p = '/Jotta/Sync/runtest.txt'
f = jfs.up(p, StringIO('12345'))
logging.info(xdump(f.f))
print f.readpartial(2,4)
f.writepartial('6789', 5)
f2 = jfs.up(p, StringIO('6789'), resume=True)
logging.info(xdump(f.f))
print f.read()
print f.readpartial(1,6)
89 changes: 89 additions & 0 deletions tests/sansmd5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# -*- encoding: utf-8 -*-
'Test jottalib without md5'
#
# This file is part of jottalib.
#
# jottalib is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# jottalib is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with jottafs. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2016 Håvard Gulldahl <[email protected]>

# metadata
__author__ = '[email protected]'

# import standardlib
import os, os.path, tempfile, time, math, logging, datetime, hashlib

import requests

import urllib3, certifi
urllib3.disable_warnings() # TODO FIX THIS

def humanizeFileSize(size):
size = abs(size)
if (size==0):
return "0B"
units = ['B','KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']
p = math.floor(math.log(size, 2)/10)
return "%.3f%s" % (size/math.pow(1024,p),units[int(p)])


class JFS(object):
def __init__(self, username, password):
self.apiversion = '2.2' # hard coded per october 2014
self.session = urllib3.connectionpool.connection_from_url('https://up.jottacloud.com',
cert_reqs='CERT_REQUIRED',
ca_certs=certifi.where())
self.username = username
self.headers = urllib3.util.make_headers(basic_auth='%s:%s' % (username, password))
self.headers.update({'User-Agent':'jottalib %s (https://github.com/havardgulldahl/jottalib)' % (__version__, ),
'X-JottaAPIVersion': self.apiversion,
})
def get(self, path):
r = self.session.request('GET', '/jfs/%s%s' % (self.username, path), headers=self.headers)
return r

def up(self, path, fileobject):
url = path.replace('www.jotta.no', 'up.jottacloud.com')

# Calculate file md5 hash
#contentlen, md5hash = calculate_hash(fileobject)
md5hash = None

log.debug('posting content (len %s, hash %s) to url %s', contentlen, md5hash, url)
now = datetime.datetime.now().isoformat()
headers = {'JMd5':md5hash,
'JCreated': now,
'JModified': now,
'X-Jfs-DeviceName': 'Jotta',
'JSize': contentlen,
'jx_csid': '',
'jx_lisence': ''
}
params = {'cphash':md5hash,}
fileobject.seek(0) # rewind read index for requests.post
fields = {'md5': ('', md5hash),
'modified': ('', now),
'created': ('', now),
'file': (os.path.basename(url), fileobject.read(), 'application/octet-stream')}
# TODO TODO: don't do fileobject.read() in previous line
# we want to have a chunked upload, read the file piece by piece
# not sure how urllib3 supports this ATM
sessheaders = self.headers.copy()
headers.update(sessheaders)
request = self.session.request_encode_body('POST',
url,
fields,
headers)

return request

0 comments on commit 1b7e188

Please sign in to comment.