Skip to content

Commit

Permalink
base64 thumbnail
Browse files Browse the repository at this point in the history
  • Loading branch information
SkywalkerSpace committed Sep 9, 2020
1 parent b7824cd commit 77765fd
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 41 deletions.
8 changes: 4 additions & 4 deletions default
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ server {
return 301 https://$host$request_uri;
}

listen 80;
server_name thumbnail.seatable.cn;
listen 80;
server_name thumbnail.seatable.cn;
return 404;
}


server {
server_name thumbnail.seatable.cn;
server_name thumbnail.seatable.cn;

listen 443 ssl;
ssl_certificate /root/.acme.sh/thumbnail.seatable.cn/fullchain.cer;
Expand All @@ -30,6 +30,6 @@ server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}

}
28 changes: 19 additions & 9 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ async def __call__(self, scope, receive, send):
"""
# request
request = HTTPRequest(**scope)
if request.method == 'OPTIONS':
response_start, response_body = gen_text_response('')
await send(response_start)
await send(response_body)
return

if request.method != 'GET':
response_start, response_body = gen_error_response(
405, 'Method %s not allowed.' % request.method)
Expand All @@ -41,18 +47,24 @@ async def __call__(self, scope, receive, send):
except Exception as e:
logger.exception(e)
response_start, response_body = gen_error_response(
400, 'Request invalid.')
400, 'Bad request.')
await send(response_start)
await send(response_body)
return

# permission
try:
permission = ThumbnailPermission(**thumbnail_info)
if not permission.check():
response_start, response_body = gen_error_response(
403, 'Forbidden.')
await send(response_start)
await send(response_body)
return
except Exception as e:
logger.exception(e)
response_start, response_body = gen_error_response(
403, 'Forbidden.')
500, 'Internal server error.')
await send(response_start)
await send(response_body)
return
Expand All @@ -61,13 +73,11 @@ async def __call__(self, scope, receive, send):
try:
etag = thumbnail_info.get('etag')
if_none_match_headers = request.headers.get('if-none-match')
if_none_match = if_none_match_headers[0].encode(
'utf-8') if if_none_match_headers else None
if_none_match = if_none_match_headers[0] if if_none_match_headers else ''

last_modified = thumbnail_info.get('last_modified')
if_modified_since_headers = request.headers.get('if-modified-since')
if_modified_since = if_modified_since_headers[0].encode(
'utf-8') if if_modified_since_headers else None
if_modified_since = if_modified_since_headers[0] if if_modified_since_headers else ''

if (if_none_match and if_none_match == etag) \
or (if_modified_since and if_modified_since == last_modified):
Expand All @@ -81,7 +91,7 @@ async def __call__(self, scope, receive, send):
# get or generate
try:
thumbnail = Thumbnail(**thumbnail_info)
body = thumbnail.body
body = thumbnail.base64_body
last_modified = thumbnail.last_modified
etag = thumbnail.etag

Expand All @@ -93,15 +103,15 @@ async def __call__(self, scope, receive, send):
except Exception as e:
logger.exception(e)
response_start, response_body = gen_error_response(
500, 'Generate failed.')
500, 'Internal server error.')
await send(response_start)
await send(response_body)
return

# ===== Not found =====
else:
response_start, response_body = gen_error_response(
404, 'Not Found.')
404, 'Not found.')
await send(response_start)
await send(response_body)
return
Expand Down
2 changes: 0 additions & 2 deletions seatable_thumbnail/constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# content type
TEXT_CONTENT_TYPE = b'text/plain'
THUMBNAIL_CONTENT_TYPE = b'image/png'


# jwt
Expand All @@ -18,7 +17,6 @@

# file type
EMPTY_BYTES = b''
THUMBNAIL_EXTENSION = 'png'
IMAGE_MODES = ('1', 'L', 'P', 'RGB', 'RGBA',)

TEXT = 'Text'
Expand Down
24 changes: 14 additions & 10 deletions seatable_thumbnail/http_response.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from seatable_thumbnail.constants import TEXT_CONTENT_TYPE, THUMBNAIL_CONTENT_TYPE, \
EMPTY_BYTES
import seatable_thumbnail.settings as settings
from seatable_thumbnail.constants import TEXT_CONTENT_TYPE, EMPTY_BYTES


def gen_response_start(status, content_type):
def gen_response_start(status):
return {
'type': 'http.response.start',
'status': status,
'headers': [
[b'Content-Type', content_type],
[b'Content-Type', TEXT_CONTENT_TYPE],
[b'Access-Control-Allow-Origin', settings.ALLOW_ORIGIN.rstrip('/').encode('utf-8')],
[b'Access-Control-Allow-Methods', b'GET,OPTIONS'],
[b'Access-Control-Allow-Credentials', b'true'],
[b'Access-Control-Allow-Headers', b'Authorization'],
]
}

Expand All @@ -20,34 +24,34 @@ def gen_response_body(body):


def gen_error_response(status, error_msg):
response_start = gen_response_start(status, TEXT_CONTENT_TYPE)
response_start = gen_response_start(status)
response_body = gen_response_body(error_msg.encode('utf-8'))

return response_start, response_body


def gen_text_response(text):
response_start = gen_response_start(200, TEXT_CONTENT_TYPE)
response_start = gen_response_start(200)
response_body = gen_response_body(text.encode('utf-8'))

return response_start, response_body


def gen_cache_response():
response_start = gen_response_start(304, TEXT_CONTENT_TYPE)
response_start = gen_response_start(304)
response_body = gen_response_body(EMPTY_BYTES)

return response_start, response_body


def gen_thumbnail_response(thumbnail, etag, last_modified):
response_start = gen_response_start(200, THUMBNAIL_CONTENT_TYPE)
response_start = gen_response_start(200)
response_body = gen_response_body(thumbnail)

# cache
if thumbnail:
response_start['headers'].append([b'Cache-Control', b'max-age=86400, public'])
response_start['headers'].append([b'ETag', etag])
response_start['headers'].append([b'Last-Modified', last_modified])
response_start['headers'].append([b'ETag', etag.encode('utf-8')])
response_start['headers'].append([b'Last-Modified', last_modified.encode('utf-8')])

return response_start, response_body
7 changes: 2 additions & 5 deletions seatable_thumbnail/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@
class ThumbnailPermission(object):
def __init__(self, **info):
self.__dict__.update(info)
self.check()

def check(self):
self.dtable = session.query(
DTables).filter_by(uuid=self.dtable_uuid).first()

if not self.has_dtable_asset_read_permission():
raise AssertionError(403, 'Permission denied.')
def check(self):
return self.has_dtable_asset_read_permission()

def has_dtable_asset_read_permission(self):
# three ways to access asset
Expand Down
10 changes: 5 additions & 5 deletions seatable_thumbnail/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from seaserv import seafile_api
from seatable_thumbnail import session
import seatable_thumbnail.settings as settings
from seatable_thumbnail.constants import EMPTY_BYTES, FILE_EXT_TYPE_MAP, \
from seatable_thumbnail.constants import FILE_EXT_TYPE_MAP, \
JWT_VERIFY, JWT_LEEWAY, JWT_AUDIENCE, JWT_ISSUER, JWT_ALGORITHM, \
IMAGE, PSD, VIDEO, XMIND
from seatable_thumbnail.models import Workspaces
Expand Down Expand Up @@ -47,7 +47,7 @@ def jwt_decode_handler(self, jwt_token):
)

def jwt_check(self):
jwt_token = self.request.query_dict['token'][0]
jwt_token = self.request.headers['authorization'][0]
self.payload = self.jwt_decode_handler(jwt_token)

def get_enable_file_type(self):
Expand Down Expand Up @@ -113,7 +113,7 @@ def resource_check(self):
thumbnail_path = os.path.join(thumbnail_dir, file_id)
os.makedirs(thumbnail_dir, exist_ok=True)
exist, last_modified = self.exist_check(thumbnail_path)
etag = b'"' + file_id.encode('utf-8') + b'"'
etag = '"' + file_id + '"'

self.resource = {
'repo_id': repo_id,
Expand All @@ -131,7 +131,7 @@ def exist_check(self, thumbnail_path):
last_modified_time = os.path.getmtime(thumbnail_path)
last_modified_time = int(last_modified_time)
last_modified = formatdate(
last_modified_time, usegmt=True).encode('utf-8')
last_modified_time, usegmt=True)
return True, last_modified
else:
return False, EMPTY_BYTES
return False, ''
2 changes: 2 additions & 0 deletions seatable_thumbnail/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
# url
URL_PREFIX = '/'
INNER_FILE_SERVER_ROOT = 'http://127.0.0.1:8082'
ALLOW_ORIGIN = 'https://cloud.seatable.cn'


# mysql
Expand All @@ -41,6 +42,7 @@
# THUMBNAIL_DIR = '/opt/seatable/seahub-data/thumbnail/'


THUMBNAIL_EXTENSION = 'jpeg'
# size(MB) limit for generate thumbnail
THUMBNAIL_IMAGE_SIZE_LIMIT = 30
THUMBNAIL_IMAGE_ORIGINAL_SIZE_LIMIT = 256
Expand Down
13 changes: 7 additions & 6 deletions seatable_thumbnail/thumbnail.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import time
import base64
import urllib.request
import urllib.parse
import zipfile
Expand All @@ -11,7 +12,7 @@
from seaserv import get_repo, get_file_size, seafile_api
import seatable_thumbnail.settings as settings
from seatable_thumbnail.constants import IMAGE_MODES, EMPTY_BYTES,\
THUMBNAIL_EXTENSION, IMAGE, PSD, VIDEO, XMIND
IMAGE, PSD, VIDEO, XMIND


class Thumbnail(object):
Expand All @@ -27,6 +28,8 @@ def get(self):
else:
self.generate()

self.base64_body = base64.b64encode(self.body)

def generate(self):
# ===== image =====
if self.file_type == IMAGE:
Expand Down Expand Up @@ -107,15 +110,13 @@ def create_image_thumbnail(self, image):
# save file
image = self.get_rotated_image(image)
image.thumbnail((self.size, self.size), Image.ANTIALIAS)
image.save(self.thumbnail_path, THUMBNAIL_EXTENSION)
image.save(self.thumbnail_path, settings.THUMBNAIL_EXTENSION)
last_modified_time = time.time()
last_modified_time = int(last_modified_time)
self.last_modified = formatdate(
last_modified_time, usegmt=True).encode('utf-8')
self.last_modified = formatdate(int(last_modified_time), usegmt=True)

# PIL to bytes
image_bytes = BytesIO()
image.save(image_bytes, THUMBNAIL_EXTENSION)
image.save(image_bytes, settings.THUMBNAIL_EXTENSION)
self.body = image_bytes.getvalue()

def get_rotated_image(self, image):
Expand Down

0 comments on commit 77765fd

Please sign in to comment.