Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions api/nostr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from secp256k1 import PrivateKey
from asgiref.sync import sync_to_async
from nostr_sdk import Keys, Client, EventBuilder, NostrSigner, Kind, Tag
from nostr_sdk import Keys, Client, EventBuilder, NostrSigner, Kind, Tag, PublicKey
from api.models import Order
from decouple import config

Expand All @@ -22,20 +22,12 @@ async def send_order_event(self, order):
if config("NOSTR_NSEC", cast=str, default="") == "":
return

print("Sending nostr event")
print("Sending nostr ORDER event")

# Initialize with coordinator Keys
keys = Keys.parse(config("NOSTR_NSEC", cast=str))
signer = NostrSigner.keys(keys)
client = Client(signer)

# Add relays and connect
await client.add_relay("ws://localhost:7777")
strfry_port = config("STRFRY_PORT", cast=str, default="7778")
await client.add_relay(f"ws://localhost:{strfry_port}")
await client.connect()
client = await self.initialize_client(keys)

robot_name = await self.get_robot_name(order)
robot_name = await self.get_user_name(order)
robot_hash_id = await self.get_robot_hash_id(order)
currency = await self.get_robot_currency(order)

Expand All @@ -45,10 +37,46 @@ async def send_order_event(self, order):
.sign_with_keys(keys)
)
await client.send_event(event)
print(f"Nostr event sent: {event.as_json()}")
print(f"Nostr ORDER event sent: {event.as_json()}")

async def send_notification_event(self, robot, order, text):
"""Creates the notification event and sends it to the coordinator relay"""
if config("NOSTR_NSEC", cast=str, default="") == "":
return

print("Sending nostr NOTIFICATION event")

keys = Keys.parse(config("NOSTR_NSEC", cast=str))
client = await self.initialize_client(keys)

tags = [
Tag.parse(
[
"order_id",
f"{config("COORDINATOR_ALIAS", cast=str).lower()}/{order.id}",
]
),
Tag.parse(["status", str(order.status)]),
]

await client.send_private_msg(PublicKey.parse(robot.nostr_pubkey), text, tags)
print("Nostr NOTIFICATION event sent")

async def initialize_client(self, keys):
# Initialize with coordinator Keys
signer = NostrSigner.keys(keys)
client = Client(signer)

# Add relays and connect
await client.add_relay("ws://localhost:7777")
strfry_port = config("STRFRY_PORT", cast=str, default="7778")
await client.add_relay(f"ws://localhost:{strfry_port}")
await client.connect()

return client

@sync_to_async
def get_robot_name(self, order):
def get_user_name(self, order):
return order.maker.username

@sync_to_async
Expand Down
7 changes: 6 additions & 1 deletion api/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Notification,
)
from api.utils import get_session
from api.tasks import nostr_send_notification_event


class Notifications:
Expand All @@ -32,8 +33,12 @@ def get_context(user):
return context

def send_message(self, order, robot, title, description=""):
"""Save a message for a user and sends it to Telegram"""
"""Save a message for a user and sends it to Telegram and/or Nostr"""
self.save_message(order, robot, title, description)
if robot.nostr_pubkey:
nostr_send_notification_event.delay(
robot_id=robot.id, order_id=order.id, text=title
)
if robot.telegram_enabled:
self.send_telegram_message(robot.telegram_chat_id, title, description)

Expand Down
15 changes: 15 additions & 0 deletions api/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,21 @@ def nostr_send_order_event(order_id=None):
return


@shared_task(name="", ignore_result=True, time_limit=120)
def nostr_send_notification_event(robot_id=None, order_id=None, text=None):
if order_id:
from api.models import Robot, Order
from api.nostr import Nostr

robot = Robot.objects.get(id=robot_id)
order = Order.objects.get(id=order_id)

nostr = Nostr()
async_to_sync(nostr.send_notification_event)(robot, order, text)

return


@shared_task(name="send_notification", ignore_result=True, time_limit=120)
def send_notification(order_id=None, chat_message_id=None, message=None):
if order_id:
Expand Down
19 changes: 3 additions & 16 deletions frontend/src/basic/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import React, { useContext } from 'react';
import { MemoryRouter, HashRouter, BrowserRouter, BrowserRouterProps } from 'react-router-dom';
import { Box, Typography, styled } from '@mui/material';
import { type UseAppStoreType, AppContext, closeAll } from '../contexts/AppContext';
import { type UseAppStoreType, AppContext } from '../contexts/AppContext';

import { NavBar, MainDialogs } from './';
import Notifications from '../components/Notifications';

import { useTranslation } from 'react-i18next';
import { GarageContext, type UseGarageStoreType } from '../contexts/GarageContext';
import Routes from './Routes';
import TopBar from './TopBar';

Expand Down Expand Up @@ -44,29 +42,18 @@ const MainBox = styled(Box)<MainBoxProps>((props) => ({

const Main: React.FC = () => {
const { t } = useTranslation();
const { settings, page, setOpen, windowSize, navbarHeight } =
useContext<UseAppStoreType>(AppContext);
const { garage } = useContext<UseGarageStoreType>(GarageContext);
const mobileView = windowSize?.width < 50;
const { settings, navbarHeight } = useContext<UseAppStoreType>(AppContext);

return (
<Router>
<Notifications
page={page}
openProfile={() => {
setOpen({ ...closeAll, profile: true });
}}
rewards={garage.getSlot()?.getRobot()?.earnedRewards}
windowWidth={windowSize?.width}
/>
{settings.network === 'testnet' ? (
<TestnetTypography color='secondary' align='center'>
<i>{t('Using Testnet Bitcoin')}</i>
</TestnetTypography>
) : (
<></>
)}
{mobileView && <TopBar />}
<TopBar />
<MainBox navbarHeight={navbarHeight}>
<Routes />
</MainBox>
Expand Down
Loading
Loading