free upload & player
This commit is contained in:
parent
862683b36e
commit
d852913692
|
|
@ -3,6 +3,7 @@ from datetime import datetime
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from sanic import response
|
from sanic import response
|
||||||
|
from sqlalchemy import and_
|
||||||
from tonsdk.boc import begin_cell, begin_dict
|
from tonsdk.boc import begin_cell, begin_dict
|
||||||
from tonsdk.utils import Address
|
from tonsdk.utils import Address
|
||||||
|
|
||||||
|
|
@ -18,6 +19,8 @@ from app.core.models.content.user_content import UserContent
|
||||||
from app.core.models.node_storage import StoredContent
|
from app.core.models.node_storage import StoredContent
|
||||||
from app.core.models._telegram import Wrapped_CBotChat
|
from app.core.models._telegram import Wrapped_CBotChat
|
||||||
from app.core._keyboards import get_inline_keyboard
|
from app.core._keyboards import get_inline_keyboard
|
||||||
|
from app.core.models.promo import PromoAction
|
||||||
|
from app.core.models.tasks import BlockchainTask
|
||||||
|
|
||||||
|
|
||||||
def valid_royalty_params(royalty_params):
|
def valid_royalty_params(royalty_params):
|
||||||
|
|
@ -101,6 +104,92 @@ async def s_api_v1_blockchain_send_new_content_message(request):
|
||||||
)
|
)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
|
promo_free_upload_available = (
|
||||||
|
3 - (request.ctx.db_session.query(PromoAction).filter(
|
||||||
|
PromoAction.user_internal_id == request.ctx.user.id,
|
||||||
|
PromoAction.action_type == 'freeUpload',
|
||||||
|
).count())
|
||||||
|
)
|
||||||
|
if request.ctx.db_session.query(BlockchainTask).filter(
|
||||||
|
and_(
|
||||||
|
BlockchainTask.user_id == request.ctx.user.id,
|
||||||
|
BlockchainTask.status != 'done',
|
||||||
|
)
|
||||||
|
).first():
|
||||||
|
make_log("Blockchain", f"User {request.ctx.user.id} already has a pending task", level='warning')
|
||||||
|
promo_free_upload_available = 0
|
||||||
|
|
||||||
|
make_log("Blockchain", f"User {request.ctx.user.id} has {promo_free_upload_available} free uploads available", level='info')
|
||||||
|
|
||||||
|
if promo_free_upload_available > 0:
|
||||||
|
promo_action = PromoAction(
|
||||||
|
user_id = str(request.ctx.user.id),
|
||||||
|
user_internal_id=request.ctx.user.id,
|
||||||
|
action_type='freeUpload',
|
||||||
|
action_ref=str(encrypted_content_cid.content_hash),
|
||||||
|
created=datetime.now()
|
||||||
|
)
|
||||||
|
request.ctx.db_session.add(promo_action)
|
||||||
|
|
||||||
|
blockchain_task = BlockchainTask(
|
||||||
|
destination=platform.address.to_string(1, 1, 1),
|
||||||
|
payload=b64encode(
|
||||||
|
begin_cell()
|
||||||
|
.store_uint(0x5491d08c, 32)
|
||||||
|
.store_uint(int.from_bytes(encrypted_content_cid.content_hash, "big", signed=False), 256)
|
||||||
|
.store_address(Address(request.ctx.user.wallet_address(request.ctx.db_session)))
|
||||||
|
.store_ref(
|
||||||
|
begin_cell()
|
||||||
|
.store_ref(
|
||||||
|
begin_cell()
|
||||||
|
.store_coins(int(0))
|
||||||
|
.store_coins(int(0))
|
||||||
|
.store_coins(int(request.json['price']))
|
||||||
|
.end_cell()
|
||||||
|
)
|
||||||
|
.store_maybe_ref(royalties_dict.end_dict())
|
||||||
|
.store_uint(0, 1)
|
||||||
|
.end_cell()
|
||||||
|
)
|
||||||
|
.store_ref(
|
||||||
|
begin_cell()
|
||||||
|
.store_ref(
|
||||||
|
begin_cell()
|
||||||
|
.store_bytes(f"{PROJECT_HOST}/api/v1.5/storage/{metadata_content.cid.serialize_v2(include_accept_type=True)}".encode())
|
||||||
|
.end_cell()
|
||||||
|
)
|
||||||
|
.store_ref(
|
||||||
|
begin_cell()
|
||||||
|
.store_ref(begin_cell().store_bytes(f"{encrypted_content_cid.serialize_v2()}".encode()).end_cell())
|
||||||
|
.store_ref(begin_cell().store_bytes(f"{image_content_cid.serialize_v2() if image_content_cid else ''}".encode()).end_cell())
|
||||||
|
.store_ref(begin_cell().store_bytes(f"{metadata_content.cid.serialize_v2()}".encode()).end_cell())
|
||||||
|
.end_cell()
|
||||||
|
)
|
||||||
|
.end_cell()
|
||||||
|
)
|
||||||
|
.end_cell().to_boc(False)
|
||||||
|
).decode(),
|
||||||
|
epoch=None, seqno=None,
|
||||||
|
created = datetime.now(),
|
||||||
|
status='wait',
|
||||||
|
user_id = request.ctx.user.id
|
||||||
|
)
|
||||||
|
request.ctx.db_session.add(blockchain_task)
|
||||||
|
request.ctx.db_session.commit()
|
||||||
|
|
||||||
|
await request.ctx.user_uploader_wrapper.send_message(
|
||||||
|
request.ctx.user.translated('p_uploadContentTxPromo').format(
|
||||||
|
title=content_title,
|
||||||
|
free_count=(promo_free_upload_available - 1)
|
||||||
|
), message_type='hint', message_meta={
|
||||||
|
'encrypted_content_hash': b58encode(encrypted_content_cid.content_hash).decode(),
|
||||||
|
'hint_type': 'uploadContentTxRequested'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return response.json({
|
||||||
|
'promoUpload': True,
|
||||||
|
})
|
||||||
|
|
||||||
await request.ctx.user_uploader_wrapper.send_message(
|
await request.ctx.user_uploader_wrapper.send_message(
|
||||||
request.ctx.user.translated('p_uploadContentTxRequested').format(
|
request.ctx.user.translated('p_uploadContentTxRequested').format(
|
||||||
title=content_title,
|
title=content_title,
|
||||||
|
|
@ -117,6 +206,7 @@ async def s_api_v1_blockchain_send_new_content_message(request):
|
||||||
begin_cell()
|
begin_cell()
|
||||||
.store_uint(0x5491d08c, 32)
|
.store_uint(0x5491d08c, 32)
|
||||||
.store_uint(int.from_bytes(encrypted_content_cid.content_hash, "big", signed=False), 256)
|
.store_uint(int.from_bytes(encrypted_content_cid.content_hash, "big", signed=False), 256)
|
||||||
|
.store_uint(0, 2)
|
||||||
.store_ref(
|
.store_ref(
|
||||||
begin_cell()
|
begin_cell()
|
||||||
.store_ref(
|
.store_ref(
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from base64 import b64decode
|
||||||
import os
|
import os
|
||||||
|
import traceback
|
||||||
|
import httpx
|
||||||
|
|
||||||
from sqlalchemy import and_
|
from sqlalchemy import and_, func
|
||||||
from tonsdk.boc import begin_cell
|
from tonsdk.boc import begin_cell, Cell
|
||||||
from tonsdk.contract.wallet import Wallets
|
from tonsdk.contract.wallet import Wallets
|
||||||
from tonsdk.utils import HighloadQueryId
|
from tonsdk.utils import HighloadQueryId
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
@ -93,7 +96,7 @@ async def main_fn(memory):
|
||||||
await toncenter.send_boc(
|
await toncenter.send_boc(
|
||||||
service_wallet.create_transfer_message(
|
service_wallet.create_transfer_message(
|
||||||
[{
|
[{
|
||||||
'address': highload_wallet.address.to_string(1, 1, 1),
|
'address': highload_wallet.address.to_string(1, 1, 0),
|
||||||
'amount': int(0.08 * 10 ** 9),
|
'amount': int(0.08 * 10 ** 9),
|
||||||
'send_mode': 1,
|
'send_mode': 1,
|
||||||
'payload': begin_cell().store_uint(0, 32).end_cell()
|
'payload': begin_cell().store_uint(0, 32).end_cell()
|
||||||
|
|
@ -122,18 +125,153 @@ async def main_fn(memory):
|
||||||
sw_seqno_value = await get_sw_seqno()
|
sw_seqno_value = await get_sw_seqno()
|
||||||
make_log("TON", f"Service running ({sw_seqno_value})", level="debug")
|
make_log("TON", f"Service running ({sw_seqno_value})", level="debug")
|
||||||
|
|
||||||
# with db_session() as session:
|
with db_session() as session:
|
||||||
# next_task = session.query(BlockchainTask).filter(
|
# Проверка отправленных сообщений
|
||||||
# BlockchainTask.status == 'wait'
|
async def process_incoming_transaction(transaction: dict):
|
||||||
# ).first()
|
transaction_hash = transaction['transaction_id']['hash']
|
||||||
# if next_task:
|
transaction_lt = str(transaction['transaction_id']['lt'])
|
||||||
# make_log("TON", f"Processing task {next_task.id}", level="info")
|
# transaction_success = bool(transaction['success'])
|
||||||
|
|
||||||
# next_task.status = 'processing'
|
async def process_incoming_message(blockchain_message: dict):
|
||||||
|
in_msg_cell = Cell.one_from_boc(b64decode(blockchain_message['msg_data']['body']))
|
||||||
|
in_msg_slice = in_msg_cell.refs[0].begin_parse()
|
||||||
|
in_msg_slice.read_uint(32)
|
||||||
|
in_msg_slice.read_uint(8)
|
||||||
|
in_msg_query_id = in_msg_slice.read_uint(23)
|
||||||
|
in_msg_created_at = in_msg_slice.read_uint(64)
|
||||||
|
in_msg_epoch = int(in_msg_created_at // (60 * 60))
|
||||||
|
in_msg_seqno = HighloadQueryId.from_query_id(in_msg_query_id).to_seqno()
|
||||||
|
in_msg_blockchain_task = (
|
||||||
|
session.query(BlockchainTask).filter(
|
||||||
|
and_(
|
||||||
|
BlockchainTask.seqno == in_msg_seqno,
|
||||||
|
BlockchainTask.epoch == in_msg_epoch,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).first()
|
||||||
|
if not in_msg_blockchain_task:
|
||||||
|
return
|
||||||
|
|
||||||
# session.commit()
|
if not (in_msg_blockchain_task.status in ['done']) or in_msg_blockchain_task.transaction_hash != transaction_hash:
|
||||||
|
in_msg_blockchain_task.status = 'done'
|
||||||
|
in_msg_blockchain_task.transaction_hash = transaction_hash
|
||||||
|
in_msg_blockchain_task.transaction_lt = transaction_lt
|
||||||
|
await session.commit()
|
||||||
|
|
||||||
|
for blockchain_message in [transaction['in_msg']]:
|
||||||
|
try:
|
||||||
|
await process_incoming_message(blockchain_message)
|
||||||
|
except BaseException as e:
|
||||||
|
pass # make_log("TON_Daemon", f"Error while processing incoming message: {e}" + '\n' + traceback.format_exc(), level='debug')
|
||||||
|
|
||||||
|
try:
|
||||||
|
sw_transactions = await toncenter.get_transactions(highload_wallet.address.to_string(1, 1, 1), limit=100)
|
||||||
|
for sw_transaction in sw_transactions:
|
||||||
|
try:
|
||||||
|
await process_incoming_transaction(sw_transaction)
|
||||||
|
except BaseException as e:
|
||||||
|
make_log("TON_Daemon", f"Error while processing incoming transaction: {e}", level="debug")
|
||||||
|
except BaseException as e:
|
||||||
|
make_log("TON_Daemon", f"Error while getting service wallet transactions: {e}", level="ERROR")
|
||||||
|
|
||||||
|
# Отправка подписанных сообщений
|
||||||
|
for blockchain_task in (
|
||||||
|
session.query(BlockchainTask).filter(
|
||||||
|
BlockchainTask.status == 'processing',
|
||||||
|
).order_by(BlockchainTask.updated.asc()).all()
|
||||||
|
):
|
||||||
|
make_log("TON_Daemon", f"Processing task (processing) {blockchain_task.id}")
|
||||||
|
query_boc = bytes.fromhex(blockchain_task.meta['signed_message'])
|
||||||
|
errors_list = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
await toncenter.send_boc(query_boc)
|
||||||
|
except BaseException as e:
|
||||||
|
errors_list.append(f"{e}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
make_log("TON_Daemon", str(
|
||||||
|
httpx.post(
|
||||||
|
'https://tonapi.io/v2/blockchain/message',
|
||||||
|
json={
|
||||||
|
'boc': query_boc.hex()
|
||||||
|
}
|
||||||
|
).text
|
||||||
|
))
|
||||||
|
except BaseException as e:
|
||||||
|
make_log("TON_Daemon", f"Error while pushing task to tonkeeper ({blockchain_task.id}): {e}", level="ERROR")
|
||||||
|
errors_list.append(f"{e}")
|
||||||
|
|
||||||
|
blockchain_task.updated = datetime.utcnow()
|
||||||
|
|
||||||
|
if blockchain_task.meta['sign_created'] + 10 * 60 < datetime.utcnow().timestamp():
|
||||||
|
# or sum([int("terminating vm with exit code 36" in e) for e in errors_list]) > 0:
|
||||||
|
make_log("TON_Daemon", f"Task {blockchain_task.id} done", level="DEBUG")
|
||||||
|
blockchain_task.status = 'done'
|
||||||
|
await session.commit()
|
||||||
|
continue
|
||||||
|
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
# Создание новых подписей
|
||||||
|
for blockchain_task in (
|
||||||
|
session.query(BlockchainTask).filter(BlockchainTask.status == 'wait').all()
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
# Check processing tasks in current epoch < 3_000_000
|
||||||
|
if (
|
||||||
|
session.query(BlockchainTask).filter(
|
||||||
|
BlockchainTask.epoch == blockchain_task.epoch,
|
||||||
|
).count() > 3_000_000
|
||||||
|
):
|
||||||
|
make_log("TON", f"Too many processing tasks in epoch {blockchain_task.epoch}", level="error")
|
||||||
|
await send_status("ton_daemon", f"working: too many tasks in epoch {blockchain_task.epoch}")
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
continue
|
||||||
|
|
||||||
|
sign_created = int(datetime.utcnow().timestamp()) - 60
|
||||||
|
try:
|
||||||
|
current_epoch = int(datetime.utcnow().timestamp() // (60 * 60))
|
||||||
|
max_epoch_seqno = (
|
||||||
|
session.query(func.max(BlockchainTask.seqno)).filter(
|
||||||
|
BlockchainTask.epoch == current_epoch
|
||||||
|
).scalar() or 0
|
||||||
|
)
|
||||||
|
current_epoch_shift = 3_000_000 if current_epoch % 2 == 0 else 0
|
||||||
|
current_seqno = max_epoch_seqno + 1 + (current_epoch_shift if max_epoch_seqno == 0 else 0)
|
||||||
|
except BaseException as e:
|
||||||
|
make_log("CRITICAL", f"Error calculating epoch,seqno: {e}", level="error")
|
||||||
|
current_epoch = 0
|
||||||
|
current_seqno = 0
|
||||||
|
|
||||||
|
blockchain_task.seqno = current_seqno
|
||||||
|
blockchain_task.epoch = current_epoch
|
||||||
|
blockchain_task.status = 'processing'
|
||||||
|
try:
|
||||||
|
query = highload_wallet.create_transfer_message(
|
||||||
|
blockchain_task.destination, int(blockchain_task.amount), HighloadQueryId.from_seqno(current_seqno),
|
||||||
|
sign_created, send_mode=1,
|
||||||
|
payload=Cell.one_from_boc(b64decode(blockchain_task.payload))
|
||||||
|
)
|
||||||
|
query_boc = query['message'].to_boc(False)
|
||||||
|
except BaseException as e:
|
||||||
|
make_log("TON", f"Error creating transfer message: {e}", level="error")
|
||||||
|
query_boc = begin_cell().end_cell().to_boc(False)
|
||||||
|
|
||||||
|
blockchain_task.meta = {
|
||||||
|
**blockchain_task.meta,
|
||||||
|
'sign_created': sign_created,
|
||||||
|
'signed_message': query_boc,
|
||||||
|
}
|
||||||
|
await session.commit()
|
||||||
|
make_log("TON", f"Created signed message for task {blockchain_task.id}" + '\n' + traceback.format_exc(), level="info")
|
||||||
|
except BaseException as e:
|
||||||
|
make_log("TON", f"Error processing task {blockchain_task.id}: {e}" + '\n' + traceback.format_exc(), level="error")
|
||||||
|
continue
|
||||||
|
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
await asyncio.sleep(1)
|
||||||
await send_status("ton_daemon", f"working (seqno={sw_seqno_value})")
|
await send_status("ton_daemon", f"working (seqno={sw_seqno_value})")
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
make_log("TON", f"Error: {e}", level="error")
|
make_log("TON", f"Error: {e}", level="error")
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ class PlayerTemplates:
|
||||||
)
|
)
|
||||||
).first())
|
).first())
|
||||||
)
|
)
|
||||||
if have_access:
|
if False and have_access:
|
||||||
full_content = self.db_session.query(StoredContent).filter_by(
|
full_content = self.db_session.query(StoredContent).filter_by(
|
||||||
hash=content.meta.get('converted_content', {}).get('low') # TODO: support high quality
|
hash=content.meta.get('converted_content', {}).get('low') # TODO: support high quality
|
||||||
).first()
|
).first()
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ class BlockchainTask:
|
||||||
id = Column(Integer, autoincrement=True, primary_key=True)
|
id = Column(Integer, autoincrement=True, primary_key=True)
|
||||||
|
|
||||||
destination = Column(String(1024), nullable=False)
|
destination = Column(String(1024), nullable=False)
|
||||||
payload = Column(String(1024), nullable=False)
|
amount = Column(String(256), nullable=False)
|
||||||
|
payload = Column(String(4096), nullable=False)
|
||||||
|
|
||||||
epoch = Column(Integer, nullable=True)
|
epoch = Column(Integer, nullable=True)
|
||||||
seqno = Column(Integer, nullable=True)
|
seqno = Column(Integer, nullable=True)
|
||||||
|
|
@ -17,6 +18,7 @@ class BlockchainTask:
|
||||||
created = Column(DateTime, nullable=False, default=datetime.now)
|
created = Column(DateTime, nullable=False, default=datetime.now)
|
||||||
updated = Column(DateTime, nullable=False, default=datetime.now)
|
updated = Column(DateTime, nullable=False, default=datetime.now)
|
||||||
|
|
||||||
|
user_id = Column(Integer, ForeignKey('users.id'), nullable=True)
|
||||||
meta = Column(JSON, nullable=False, default={})
|
meta = Column(JSON, nullable=False, default={})
|
||||||
status = Column(String(256), nullable=False)
|
status = Column(String(256), nullable=False)
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -194,3 +194,12 @@ msgstr "🔗 Поделиться"
|
||||||
|
|
||||||
msgid "p_shareLinkContext"
|
msgid "p_shareLinkContext"
|
||||||
msgstr "🎉 Наслаждайтесь {title} на MY!"
|
msgstr "🎉 Наслаждайтесь {title} на MY!"
|
||||||
|
|
||||||
|
msgid "p_uploadContentTxPromo"
|
||||||
|
msgstr ""
|
||||||
|
"🎉 Вам доступно ещё <b>{free_count}</b> бесплатных приветственных загрузок контента! "
|
||||||
|
"Контент <b>{title}</b> уже находится в процессе загрузки. Как только блокчейн обработает транзакцию, "
|
||||||
|
"вы получите NFT-лицензию."
|
||||||
|
|
||||||
|
msgid "p_playerContext_contentNotReady"
|
||||||
|
msgstr "⚠️ Контент, который вы хотите просмотреть, ещё не готов. Пожалуйста, попробуйте позже."
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue