6 Commits

Author SHA1 Message Date
8f8948b89d Add github sync for i2p-rs
Some checks failed
Sync Primary Repository to GitHub Mirror / sync (push) Has been cancelled
2025-05-10 18:54:40 -04:00
idk
0e8d8a2959 Merge pull request #22 from snex/master 2024-04-03 11:32:12 -04:00
87b140e3b4 remove erroneous linebreak in SAM client 2024-04-01 14:30:58 -07:00
idk
fbde12b629 Merge pull request #20 from a-0-dev/master
Allow passing SAM options on I2PListener
2023-11-23 09:08:45 -05:00
286b06d2c4 Revert change: SAMOptions are passed by value again (as opposed to call by reference, introduced in last commit) 2023-11-21 16:01:13 +01:00
1d4ce43a70 Improved creation of I2pListeners
- Added `I2pListenerBuilder`, which covers the functionality of `I2pListener::bind()`, `I2pListener::bind_with_session(...)`, `I2pListener::bind_via(...)` and `I2pListener::bind_addr(...)`.
- Added parameter `options: &SAMOptions` to functions creating/instanciating streams or listeners, except the "light versions" `I2pStream::connect()` and `I2pDatagramSocket::bind(addr)`
2023-11-21 15:44:04 +01:00
5 changed files with 200 additions and 24 deletions

66
.github/workflows/sync.yaml vendored Normal file
View File

@ -0,0 +1,66 @@
# GitHub Actions workflow file to sync an external repository to this GitHub mirror.
# This file was automatically generated by go-github-sync.
#
# The workflow does the following:
# - Runs on a scheduled basis (and can also be triggered manually)
# - Clones the GitHub mirror repository
# - Fetches changes from the primary external repository
# - Applies those changes to the mirror repository
# - Pushes the updated content back to the GitHub mirror
#
# Authentication is handled by the GITHUB_TOKEN secret provided by GitHub Actions.
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Validate Github Actions Environment
run: if [ "$GITHUB_ACTIONS" != "true" ]; then echo 'This script must be run in a GitHub Actions environment.'; exit 1; fi
- name: Checkout GitHub Mirror
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Configure Git
run: |-
git config user.name 'GitHub Actions'
git config user.email 'actions@github.com'
- env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
name: Sync Primary Repository
run: |-
# Add the primary repository as a remote
git remote add primary https://i2pgit.org/I2P_Developers/i2p-rs.git
# Fetch the latest changes from the primary repository
git fetch primary
# Check if the primary branch exists in the primary repository
if git ls-remote --heads primary master | grep -q master; then
echo "Primary branch master found in primary repository"
else
echo "Error: Primary branch master not found in primary repository"
exit 1
fi
# Check if we're already on the mirror branch
if git rev-parse --verify --quiet master; then
git checkout master
else
# Create the mirror branch if it doesn't exist
git checkout -b master
fi
# Force-apply all changes from primary, overriding any conflicts
echo "Performing force sync from primary/master to master"
git reset --hard primary/master
# Push changes back to the mirror repository
git push origin master
name: Sync Primary Repository to GitHub Mirror
"on":
push: {}
schedule:
- cron: 0 * * * *
workflow_dispatch: {}

View File

@ -3,6 +3,7 @@ use std::net::{SocketAddr, ToSocketAddrs};
use crate::error::{Error, ErrorKind};
use crate::net::{I2pSocketAddr, ToI2pSocketAddrs};
use crate::sam::DEFAULT_API;
use crate::sam_options::SAMOptions;
/// Unimplemented
///
@ -51,19 +52,21 @@ impl I2pDatagramSocket {
/// let socket = I2pDatagramSocket::bind("127.0.0.1:34254").expect("couldn't bind to address");
/// ```
pub fn bind<A: ToI2pSocketAddrs>(addr: A) -> Result<I2pDatagramSocket, Error> {
I2pDatagramSocket::bind_via(DEFAULT_API, addr)
I2pDatagramSocket::bind_via(DEFAULT_API, addr, SAMOptions::default())
}
pub fn bind_via<A: ToSocketAddrs, B: ToI2pSocketAddrs>(
sam_addr: A,
addr: B,
options: SAMOptions
) -> Result<I2pDatagramSocket, Error> {
super::each_i2p_addr(sam_addr, addr, I2pDatagramSocket::bind_addr).map_err(|e| e.into())
super::each_i2p_addr(sam_addr, addr, options,I2pDatagramSocket::bind_addr).map_err(|e| e.into())
}
fn bind_addr(
_sam_addr: &SocketAddr,
_addr: &I2pSocketAddr,
_options: SAMOptions
) -> Result<I2pDatagramSocket, Error> {
unimplemented!();
}
@ -175,15 +178,16 @@ impl I2pDatagramSocket {
/// socket.connect("127.0.0.1:8080").expect("connect function failed");
/// ```
pub fn connect<A: ToI2pSocketAddrs>(&self, addr: A) -> Result<(), Error> {
self.connect_via(DEFAULT_API, addr)
self.connect_via(DEFAULT_API, addr, SAMOptions::default())
}
pub fn connect_via<A: ToSocketAddrs, B: ToI2pSocketAddrs>(
&self,
sam_addr: A,
addr: B,
options: SAMOptions,
) -> Result<(), Error> {
super::each_i2p_addr(sam_addr, addr, |_sam_addr, _addr| unimplemented!())
super::each_i2p_addr(sam_addr, addr, options, |_sam_addr, _addr, _opts| unimplemented!())
}
/// Sends data on the socket to the remote address to which it is connected.

View File

@ -1,10 +1,11 @@
use crate::error::{Error, ErrorKind};
use crate::sam_options::SAMOptions;
use std::net::{SocketAddr, ToSocketAddrs};
pub use self::addr::{I2pSocketAddr, ToI2pSocketAddrs};
pub use self::datagram::I2pDatagramSocket;
pub use self::i2p::I2pAddr;
pub use self::streaming::{I2pListener, I2pStream};
pub use self::streaming::{I2pListenerBuilder, I2pListener, I2pStream};
mod addr;
mod datagram;
@ -16,15 +17,16 @@ mod test;
fn each_i2p_addr<A: ToSocketAddrs, B: ToI2pSocketAddrs, F, T>(
sam_addr: A,
addr: B,
opts: SAMOptions,
mut f: F,
) -> Result<T, Error>
where
F: FnMut(&SocketAddr, &I2pSocketAddr) -> Result<T, Error>,
F: FnMut(&SocketAddr, &I2pSocketAddr, SAMOptions) -> Result<T, Error>,
{
let mut last_err = None;
for addr in addr.to_socket_addrs()? {
for sam_addr in sam_addr.to_socket_addrs()? {
match f(&sam_addr, &addr) {
match f(&sam_addr, &addr, opts.clone()) {
Ok(l) => return Ok(l),
Err(e) => last_err = Some(e),
}
@ -33,13 +35,13 @@ where
Err(last_err.unwrap_or(ErrorKind::UnresolvableAddress.into()))
}
fn each_addr<A: ToSocketAddrs, F, T>(sam_addr: A, mut f: F) -> Result<T, Error>
fn each_addr<A: ToSocketAddrs, F, T>(sam_addr: A, opts: SAMOptions, mut f: F) -> Result<T, Error>
where
F: FnMut(&SocketAddr) -> Result<T, Error>,
F: FnMut(&SocketAddr, SAMOptions) -> Result<T, Error>,
{
let mut last_err = None;
for sam_addr in sam_addr.to_socket_addrs()? {
match f(&sam_addr) {
match f(&sam_addr, opts.clone()) {
Ok(l) => return Ok(l),
Err(e) => last_err = Some(e),
}

View File

@ -8,6 +8,7 @@ use std::time::Duration;
use crate::error::{Error, ErrorKind};
use crate::net::{I2pAddr, I2pSocketAddr, ToI2pSocketAddrs};
use crate::sam::{Session, StreamConnect, StreamForward, DEFAULT_API};
use crate::sam_options::SAMOptions;
/// A structure which represents an I2P stream between a local socket and a
/// remote socket.
@ -74,7 +75,7 @@ impl I2pStream {
/// }
/// ```
pub fn connect<A: ToI2pSocketAddrs>(addr: A) -> Result<I2pStream, Error> {
I2pStream::connect_via(DEFAULT_API, addr)
I2pStream::connect_via(DEFAULT_API, addr, SAMOptions::default())
}
/// Same as `connect` but reuses an existing SAM session.
@ -92,12 +93,13 @@ impl I2pStream {
pub fn connect_via<A: ToSocketAddrs, B: ToI2pSocketAddrs>(
sam_addr: A,
addr: B,
options: SAMOptions,
) -> Result<I2pStream, Error> {
super::each_i2p_addr(sam_addr, addr, I2pStream::connect_addr).map_err(|e| e.into())
super::each_i2p_addr(sam_addr, addr, options, I2pStream::connect_addr).map_err(|e| e.into())
}
fn connect_addr(sam_addr: &SocketAddr, addr: &I2pSocketAddr) -> Result<I2pStream, Error> {
let stream = StreamConnect::new(sam_addr, &addr.dest().string(), addr.port())?;
fn connect_addr(sam_addr: &SocketAddr, addr: &I2pSocketAddr, options: SAMOptions) -> Result<I2pStream, Error> {
let stream = StreamConnect::new(sam_addr, &addr.dest().string(), addr.port(), options)?;
Ok(I2pStream { inner: stream })
}
@ -295,11 +297,11 @@ impl I2pListener {
}
pub fn bind_via<A: ToSocketAddrs>(sam_addr: A) -> Result<I2pListener, Error> {
super::each_addr(sam_addr, I2pListener::bind_addr).map_err(|e| e.into())
super::each_addr(sam_addr, SAMOptions::default(), I2pListener::bind_addr).map_err(|e| e.into())
}
fn bind_addr(sam_addr: &SocketAddr) -> Result<I2pListener, Error> {
let forward = StreamForward::new(sam_addr)?;
fn bind_addr(sam_addr: &SocketAddr, options: SAMOptions) -> Result<I2pListener, Error> {
let forward = StreamForward::new(sam_addr, options)?;
Ok(I2pListener { forward })
}
@ -397,3 +399,103 @@ impl<'a> Iterator for Incoming<'a> {
Some(self.listener.accept().map(|p| p.0))
}
}
/// A helper struct for creating `I2pListener`s.
///
/// # Examples
///
/// ```no_run
/// use i2p::net::{I2pListenerBuilder, I2pStream};
///
/// let listener = I2pListenerBuilder::new().build()?;
///
/// fn handle_client(stream: I2pStream) {
/// // ...
/// }
///
/// // accept connections and process them serially
/// for stream in listener.incoming() {
/// match stream {
/// Ok(stream) => {
/// handle_client(stream);
/// }
/// Err(e) => { /* connection failed */ }
/// }
/// }
/// ```
pub struct I2pListenerBuilder {
session: Option<Session>,
addrs: Vec<SocketAddr>,
options: SAMOptions,
}
impl Default for I2pListenerBuilder {
fn default() -> Self {
I2pListenerBuilder {
session: None,
addrs: vec![],
options: Default::default()
}
}
}
impl I2pListenerBuilder {
/// Build an `I2pListener` and bind to socket addresses using previously
/// defined settings.
///
/// If none of `with_session`, `with_addr` or `with_addrs` were called, the
/// listener will bind to `crate::sam::DEFAULT_API`.
///
/// If `with_options` was not called, defaults to `SAMOptions::default()`
///
/// If `with_session` was called, all other settings will be ignored.
pub fn build(mut self) -> Result<I2pListener, Error> {
if let Some(s) = self.session {
Ok(I2pListener {
forward: StreamForward::with_session(&s)?
})
}
else {
// Default to DEFAULT_API if no socket address has been set manually
if self.addrs.len() == 0 {
self.addrs.extend(ToSocketAddrs::to_socket_addrs(DEFAULT_API)?);
}
super::each_addr(
self.addrs.as_slice(),
self.options,
I2pListener::bind_addr
).map_err(|e| e.into())
}
}
/// Makes this builder recreate an I2pListener from the specified session.
/// According to the SAMv3 protocol, SAM options can only be set upon
/// session creation. Therefore, `I2pListenerBuilder::build(...)` will
/// ignore any options set using `with_options` if recreating a listener
/// using a previous session.
pub fn with_session(mut self, session: Session) -> Self {
self.session = Some(session);
self
}
/// Add `address` to the list of socket addresses to bind to
pub fn with_addr(mut self, address: SocketAddr) -> Self {
self.addrs.push(address);
self
}
/// Add all addresses derived from `addresses` to the list of socket
/// addresses to bind to
pub fn with_addrs<A: ToSocketAddrs>(mut self, addresses: A) -> Result<Self, Error> {
self.addrs.extend(addresses.to_socket_addrs()?);
Ok(self)
}
/// Use the SAMOptions specified when building the `I2pListener`
pub fn with_options(mut self, opts: SAMOptions) -> Self {
self.options = opts;
self
}
}

View File

@ -207,25 +207,26 @@ impl Session {
pub fn from_destination<A: ToSocketAddrs>(
sam_addr: A,
destination: &str,
options: SAMOptions,
) -> Result<Session, Error> {
Self::create(
sam_addr,
destination,
&nickname(),
SessionStyle::Stream,
SAMOptions::default(),
options,
)
}
/// Convenience constructor to create a new transient session with an
/// auto-generated nickname.
pub fn transient<A: ToSocketAddrs>(sam_addr: A) -> Result<Session, Error> {
pub fn transient<A: ToSocketAddrs>(sam_addr: A, options: SAMOptions) -> Result<Session, Error> {
Self::create(
sam_addr,
"TRANSIENT",
&nickname(),
SessionStyle::Stream,
SAMOptions::default(),
options,
)
}
@ -260,8 +261,9 @@ impl StreamConnect {
sam_addr: A,
destination: &str,
port: u16,
options: SAMOptions,
) -> Result<StreamConnect, Error> {
let session = Session::transient(sam_addr)?;
let session = Session::transient(sam_addr, options)?;
Self::with_session(&session, destination, port)
}
@ -272,7 +274,7 @@ impl StreamConnect {
let dest = sam.naming_lookup(dest)?;
let mut stream_msg = format!(
"STREAM CONNECT ID={nickname} DESTINATION={destination} SILENT=false\n",
"STREAM CONNECT ID={nickname} DESTINATION={destination} SILENT=false",
nickname = session.nickname,
destination = dest,
);
@ -353,9 +355,9 @@ pub struct StreamForward {
}
impl StreamForward {
pub fn new<A: ToSocketAddrs>(sam_addr: A) -> Result<StreamForward, Error> {
pub fn new<A: ToSocketAddrs>(sam_addr: A, options: SAMOptions) -> Result<StreamForward, Error> {
Ok(StreamForward {
session: Session::transient(sam_addr)?,
session: Session::transient(sam_addr, options)?,
})
}