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

feat: udp connection #8

Merged
merged 13 commits into from
Apr 2, 2024
11 changes: 10 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,20 @@ jobs:
with:
submodules: true

- name: MSYS2 (Windows amd64)
if: ${{ matrix.target.os == 'windows' && matrix.target.cpu == 'amd64' }}
uses: msys2/setup-msys2@v2
with:
path-type: inherit
install: >-
base-devel
git
mingw-w64-x86_64-toolchain
- uses: iffy/install-nim@v3
with:
version: ${{ matrix.nim }}


- name: Install deps
run: |
nimble install -dy
Expand Down
12 changes: 12 additions & 0 deletions webrtc/errors.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Nim-WebRTC
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.

type
# Base exception for nim-webrtc
WebRtcError* = object of CatchableError
89 changes: 89 additions & 0 deletions webrtc/udp_connection.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Nim-WebRTC
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.

import errors
import chronos, chronicles

logScope:
topics = "webrtc udp"

# UdpConn is a small wrapper of the chronos DatagramTransport.
# It's the simplest solution we found to store the message and
# the remote address used by the underlying protocols (dtls/sctp etc...)

type
WebRtcUdpError = object of WebRtcError

UdpPacketInfo* = tuple
message: seq[byte]
raddr: TransportAddress

UdpConn* = ref object
laddr*: TransportAddress
udp: DatagramTransport
dataRecv: AsyncQueue[UdpPacketInfo]
closed: bool

proc init*(self: UdpConn, laddr: TransportAddress) =
lchenut marked this conversation as resolved.
Show resolved Hide resolved
## Initialize an Udp Connection
##
self.laddr = laddr
self.closed = false

proc onReceive(
udp: DatagramTransport,
raddr: TransportAddress
) {.async: (raises: []), gcsafe.} =
# On receive Udp message callback, store the
# message with the corresponding remote address
try:
trace "UDP onReceive"
let msg = udp.getMessage()
self.dataRecv.addLastNoWait((msg, raddr))
except CatchableError as exc:
raiseAssert(exc.msg)

self.dataRecv = newAsyncQueue[UdpPacketInfo]()
self.udp = newDatagramTransport(onReceive, local = laddr)

proc close*(self: UdpConn) =
## Close an Udp Connection
##
if self.closed:
debug "Trying to close an already closed UdpConn"
return
self.closed = true
self.udp.close()

proc write*(
self: UdpConn,
raddr: TransportAddress,
msg: seq[byte]
) {.async: (raises: [CancelledError, WebRtcUdpError]).} =
## Write a message on Udp to a remote address `raddr`
##
if self.closed:
debug "Try to write on an already closed UdpConn"
return
trace "UDP write", msg
try:
await self.udp.sendTo(raddr, msg)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arnetheduck In this case where we don't need to use the actual value that will be returned by the Future, should we do like it's done here or remove the await/async and return the Future from sendTo?

except TransportError as exc:
raise (ref WebRtcUdpError)(msg: exc.msg)
lchenut marked this conversation as resolved.
Show resolved Hide resolved
except CancelledError as exc:
lchenut marked this conversation as resolved.
Show resolved Hide resolved
raise exc

proc read*(self: UdpConn): Future[UdpPacketInfo] {.async: (raises: [CancelledError]).} =
## Read the next received Udp message
##
if self.closed:
debug "Try to read on an already closed UdpConn"
return
trace "UDP read"
return await self.dataRecv.popFirst()
lchenut marked this conversation as resolved.
Show resolved Hide resolved
Loading