Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send broadcasts as notifications #78

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog for Palaver ZNC Module

## 1.3.0 (01/04/2023)

- Send ZNC broadcasts as push notifications to all clients.

## 1.2.2 (18/09/2022)

- Retry sending push notification on failure.
Expand Down
19 changes: 18 additions & 1 deletion palaver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#define REQUIRESSL

#define ZNC_PALAVER_VERSION "1.2.2"
#define ZNC_PALAVER_VERSION "1.3.0"

#include <algorithm>

Expand Down Expand Up @@ -345,6 +345,10 @@ class CDevice {
return m_bShowMessagePreview;
}

bool HasClients() const {
return !m_mClientNetworkIDs.empty();
}

bool HasClient(const CClient& client) const {
bool bHasClient = false;

Expand Down Expand Up @@ -1272,6 +1276,19 @@ class CPalaverMod : public CModule {
return CONTINUE;
}

virtual EModRet OnBroadcast(CString& sMessage) {
for (std::vector<CDevice*>::const_iterator it = m_vDevices.begin();
it != m_vDevices.end(); ++it)
{
CDevice& device = **it;
if (!device.HasClients()) {
device.SendNotification(*this, "ZNC Admin", sMessage, NULL);
}
}

return CONTINUE;
}

// MARK: - Commands

void HandleTestCommand(const CString& sLine) {
Expand Down
70 changes: 70 additions & 0 deletions test/test_broadcast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import asyncio
import json
from test.utils import (
assert_user_agent,
get_znc_version,
open_registered_znc_connection,
read_headers,
read_push_request,
requires_znc_version,
setUp,
tearDown,
)

import pytest
import pytest_asyncio

# All test coroutines will be treated as marked.
pytestmark = pytest.mark.asyncio


async def test_receiving_broadcast(znc):
reader, writer = znc

async def connected(reader, writer):
headers, body = await read_push_request(reader)
assert headers['Authorization'] == 'Bearer 9167e47b01598af7423e2ecd3d0a3ec4'
assert json.loads(body.decode('utf-8')) == {
'badge': 1,
'message': 'test',
'sender': 'ZNC Admin',
}

writer.write(b'HTTP/1.1 204 No Content\r\n\r\n')
await writer.drain()
writer.close()

connected.called = True

server = await asyncio.start_server(connected, host='127.0.0.1', port=0)
await asyncio.sleep(0.2)
addr = server.sockets[0].getsockname()
url = f'http://{addr[0]}:{addr[1]}/push'

writer.write(
b'PALAVER IDENTIFY 9167e47b01598af7423e2ecd3d0a3ec4 611d3a30a3d666fc491cdea0d2e1dd6e b758eaab1a4611a310642a6e8419fbff\r\n'
)
await writer.drain()

line = await reader.readline()
assert line == b'PALAVER REQ *\r\n'

writer.write(
b'PALAVER BEGIN 9167e47b01598af7423e2ecd3d0a3ec4 611d3a30a3d666fc491cdea0d2e1dd6e\r\n'
)
writer.write(f'PALAVER SET PUSH-ENDPOINT {url}\r\n'.encode('utf-8'))
writer.write(b'PALAVER END\r\n')
writer.write(b'QUIT :Bye\r\n')
await writer.drain()
writer.close()
await writer.wait_closed()

reader, writer = await open_registered_znc_connection()
writer.write(b'PRIVMSG *status :broadcast test\r\n')
await writer.drain()

await asyncio.sleep(0.2)
server.close()
await server.wait_closed()

assert connected.called
22 changes: 13 additions & 9 deletions test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,7 @@
from semantic_version import Version


async def setUp():
running_as_root = os.getuid() == 0
allow_root = ' --allow-root' if running_as_root else ''

proc = await asyncio.create_subprocess_shell(
f'znc -d test/fixtures --foreground --debug{allow_root}'
)
await asyncio.sleep(31 if running_as_root else 1)

async def open_registered_znc_connection():
(reader, writer) = await asyncio.open_connection('localhost', 6698)
writer.write(b'CAP LS 302\r\n')

Expand All @@ -32,6 +24,18 @@ async def setUp():

line = await reader.readline()
assert line == b':irc.znc.in 001 admin :Welcome to ZNC\r\n'
return (reader, writer)


async def setUp():
running_as_root = os.getuid() == 0
allow_root = ' --allow-root' if running_as_root else ''

proc = await asyncio.create_subprocess_shell(
f'znc -d test/fixtures --foreground --debug{allow_root}'
)
await asyncio.sleep(31 if running_as_root else 1)
reader, writer = await open_registered_znc_connection()

return (proc, reader, writer)

Expand Down