Skip to content

Commit

Permalink
perf: stop propagation if auth is called by user
Browse files Browse the repository at this point in the history
- Stop propagation if auth is called by user to avoid duplicate auth request.
- Update docker-publish.yml.
- Reply more error message.
- Fix progress error when uploading from url with large file.
  • Loading branch information
hlf20010508 committed Sep 19, 2023
1 parent 172fa99 commit 36bc9f3
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 37 deletions.
34 changes: 23 additions & 11 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,55 @@ name: Publish Docker

on:
release:
types: [published]
types: [published]
branches:
- 'master'
workflow_dispatch:

env:
REPO: hlf01/telegram-onedrive

permissions:
contents: read


run-name: ${{ github.event_name == 'workflow_dispatch' && 'build dev' || github.event.release.name }}

jobs:
build:
runs-on: ubuntu-latest
if: github.repository_owner == 'hlf20010508'
steps:
- name: Get version
id: get_version
run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\//}

- name: Checkout
uses: actions/checkout@v3

- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build and push image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v5
with:
file: Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ env.REPO }}:${{ github.event.release.name }},${{ env.REPO }}:latest
if: github.event_name == 'release' && github.event.action == 'published'

- name: Build and push image dev
uses: docker/build-push-action@v5
with:
file: Dockerfile
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ env.REPO }}:${{ steps.get_version.outputs.VERSION }},${{ env.REPO }}:latest
tags: ${{ env.REPO }}:dev
if: github.event_name == 'workflow_dispatch'
53 changes: 36 additions & 17 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ async def delete_message(message):
await message.delete()


# if message is not edited, it will raise MessageNotModifiedError
async def edit_message(bot, event, message):
try:
await bot.edit_message(event, message)
except:
pass


async def check_in_group(event):
if isinstance(event.message.peer_id, types.PeerUser):
await event.respond('''
Expand All @@ -110,7 +118,7 @@ async def res_not_login(event):
await event.respond('''
You haven't logined to Telegram.
''')
await auth(event)
await auth(event, propagate=True)


async def download_part(client, input_location, offset, part_size):
Expand Down Expand Up @@ -182,7 +190,7 @@ def get_link(string):
return link
else:
return False
except Exception:
except:
return False


Expand Down Expand Up @@ -214,7 +222,7 @@ async def help(event):


@tg_bot.on(events.NewMessage(pattern="/auth", incoming=True, from_users=tg_user_name))
async def auth(event):
async def auth(event, propagate=False):
await check_in_group(event)
auth_server = subprocess.Popen(('python', 'auth_server.py'))
async with tg_bot.conversation(event.chat_id) as conv:
Expand Down Expand Up @@ -268,6 +276,8 @@ async def od_code_callback():
status_bar = await conv.send_message("Status:\n\nNo job yet.")
await tg_bot.pin_message(event.chat_id, status_bar)
auth_server.kill()
if not propagate:
raise events.StopPropagation


@tg_bot.on(events.NewMessage(pattern="/autoDelete", incoming=True, from_users=tg_user_name))
Expand Down Expand Up @@ -322,6 +332,8 @@ async def url(event):
try:
cmd = cmd_parser(event)
_url = cmd[0]
# lest the url is bold
_url = _url.strip().strip('*')
name = _url.split('/')[-1]
except:
await event.reply('''
Expand All @@ -336,33 +348,40 @@ async def url(event):
raise events.StopPropagation

try:
logger('upload url: %s' % _url)
progress_url = onedrive.upload_from_url(_url)
print(progress_url)
progress = onedrive.upload_from_url_progress(progress_url)
logger('progress url: %s' % progress_url)
except Exception as e:
await event.reply(logger(e))

try:
response = onedrive.upload_from_url_progress(progress_url)
progress = response.content
while progress['status'] in ['notStarted', 'inProgress']:
status = "Uploaded: %.2f%%" % float(progress['percentageComplete'])
logger(status)
msg_link = 'https://t.me/c/%d/%d'%(event.message.peer_id.channel_id, event.message.id)
await tg_bot.edit_message(status_bar, 'Status:\n\n%s\n\n%s'%(msg_link, status))
await edit_message(tg_bot, status_bar, 'Status:\n\n%s\n\n%s'%(msg_link, status))
await asyncio.sleep(5)
progress = onedrive.upload_from_url_progress(progress_url)
response = onedrive.upload_from_url_progress(progress_url)
progress = response.content

status = "Uploaded: %.2f%%" % float(progress['percentageComplete'])
logger(status)
if 'fail' not in str(progress) and 'error' not in str(progress):
if 'fail' not in str(progress) and 'error' not in str(progress) and 'Error' not in str(progress) and 'Fail' not in str(progress):
logger("File uploaded to %s"%os.path.join(onedrive.remote_root_path, name))
msg_link = 'https://t.me/c/%d/%d'%(event.message.peer_id.channel_id, event.message.id)
await tg_bot.edit_message(status_bar, 'Status:\n\n%s\n\n%s'%(msg_link, status))
await edit_message(tg_bot, status_bar, 'Status:\n\n%s\n\n%s'%(msg_link, status))
if not delete_flag:
await event.reply('Done.')
await delete_message(event)
await tg_bot.edit_message(status_bar, 'Status:\n\nNo job yet.')
await edit_message(tg_bot, status_bar, 'Status:\n\nNo job yet.')
else:
await event.reply(logger('Error: something is wrong\n\nResponse: %s' % progress))
await event.reply(logger('Error: something is wrong\n\nUpload url: %s\nProgress url: %s\n\nResponse: %s' % (_url, progress_url, progress)))
await event.reply(logger("Analysis: try again later, or offer a proper url"))

except Exception as e:
await event.reply('Error: %s\nResponse: %s' % (logger(e), logger(progress)))
await event.reply('Error: %s\nUpload url: %s\nProgress url: %s\n\nResponse: %s' % (logger(e), _url, progress_url, logger(progress)))
try:
if progress['errorCode'] == 'ParameterIsTooLong':
await event.reply(logger("Analysis: url too long.OneDrive API doesn't support long url."))
Expand Down Expand Up @@ -410,7 +429,7 @@ async def callback(current, total):
status = "Uploaded %.2fMB out of %.2fMB: %.2f%%"% (current, total, current / total * 100)
logger(status)
msg_link = 'https://t.me/c/%d/%d'%(event.message.peer_id.channel_id, event.message.id)
await tg_bot.edit_message(status_bar, 'Status:\n\n%s\n\n%s'%(msg_link, status))
await edit_message(tg_bot, status_bar, 'Status:\n\n%s\n\n%s'%(msg_link, status))

if event.media and not isinstance(event.media, types.MessageMediaWebPage):
message = await tg_client.get_messages(event.message.peer_id, ids=event.message.id)
Expand All @@ -424,7 +443,7 @@ async def callback(current, total):
await multi_parts_uploader(tg_client, message.media.document, name, progress_callback=callback)
logger("File uploaded to %s" % os.path.join(remote_root_path, name))
await delete_message(message)
await tg_bot.edit_message(status_bar, "Status:\n\nNo job yet.")
await edit_message(tg_bot, status_bar, "Status:\n\nNo job yet.")

if "photo" in event.media.to_dict().keys():
if message.media:
Expand All @@ -435,7 +454,7 @@ async def callback(current, total):
onedrive.stream_upload(buffer, name)
logger("File uploaded to %s" % os.path.join(remote_root_path, name))
await delete_message(message)
await tg_bot.edit_message(status_bar, "Status:\n\nNo job yet.")
await edit_message(tg_bot, status_bar, "Status:\n\nNo job yet.")
except Exception as e:
await event.reply('Error: %s' % logger(e))

Expand Down Expand Up @@ -466,15 +485,15 @@ async def callback(current, total):
await multi_parts_uploader(tg_client, message.media.document, name, progress_callback=callback)
logger("File uploaded to %s" % os.path.join(remote_root_path, name))
await delete_message(event)
await tg_bot.edit_message(status_bar, "Status:\n\nNo job yet.")
await edit_message(tg_bot, status_bar, "Status:\n\nNo job yet.")

if "photo" in message.media.to_dict().keys():
name = "%d%s" % (message.media.photo.id, message.file.ext)
buffer = await message.download_media(file=bytes, progress_callback=callback)
onedrive.stream_upload(buffer, name)
logger("File uploaded to %s" % os.path.join(remote_root_path, name))
await delete_message(event)
await tg_bot.edit_message(status_bar, "Status:\n\nNo job yet.")
await edit_message(tg_bot, status_bar, "Status:\n\nNo job yet.")

except Exception as e:
await event.reply('Error: %s' % logger(e))
Expand Down
42 changes: 33 additions & 9 deletions onedrive.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@

from onedrivesdk import HttpProvider, AuthProvider, OneDriveClient
from onedrivesdk.options import HeaderOption
from onedrivesdk.error import OneDriveError
from onedrivesdk.error import OneDriveError, ErrorCode
from onedrivesdk.model.upload_session import UploadSession
from onedrivesdk.model.item import Item
from onedrivesdk.request.item_create_session import ItemCreateSessionRequestBuilder
from onedrivesdk.request.item_request_builder import ItemRequestBuilder
from onedrivesdk.request_builder_base import RequestBuilderBase
from onedrivesdk.request_base import RequestBase
from onedrivesdk.http_response import HttpResponse
import json
import asyncio
import time

def authenticate_request(self, request):
if self._session is None:
Expand All @@ -33,6 +35,11 @@ def authenticate_request(self, request):
def create_session(self, item=None):
return ItemCreateSessionRequestBuilder(self.append_to_request_url("createUploadSession"), self._client, item=item)

def http_response_init(self, status, headers, content):
self._status = status
self._headers = headers
self._content = content

class Onedrive:
def __init__(self, client_id, client_secret, redirect_uri, remote_root_path):
api_base_url = "https://graph.microsoft.com/v1.0/"
Expand Down Expand Up @@ -139,13 +146,29 @@ def upload_from_url(self, url):
}
raise OneDriveError(response_dict, response.status)

def upload_from_url_progress(self, url):
response = self.client.http_provider.send(
method="GET",
headers={},
url=url
)
response = json.loads(response.content)
def upload_from_url_progress(self, url):
tries = 0
while tries < 5:
response = self.client.http_provider.send(
method="GET",
headers={},
url=url
)
if response.status >= 200 and response.status < 300:
break
else:
tries += 1
time.sleep(0.1)
continue
try:
response._content = json.loads(response.content)
except:
response._content = {
"error": {
"code": ErrorCode.Malformed,
"message": "The following invalid JSON was returned:\n%s" % response.content
}
}
return response


Expand Down Expand Up @@ -220,4 +243,5 @@ def post(self, begin, length, buffer, options=None):

# Overwrite the standard upload operation to use this one
AuthProvider.authenticate_request = authenticate_request
ItemRequestBuilder.create_session = create_session
ItemRequestBuilder.create_session = create_session
HttpResponse.__init__ = http_response_init

0 comments on commit 36bc9f3

Please sign in to comment.