Skip to content

Commit

Permalink
Add UDP, update Scanner struct to fix bugged looping. Added scan_rune…
Browse files Browse the repository at this point in the history
…s split function for scanner. (#45)

* wip udp

* wip udp

* reworking listener, connectoin, etc

* udp listener and socket working...I think

* delete comments

* revert dial change

* update dial example

* fixed examples

* wip refactoring structs to use span for read trait. Scanner still needs some work

* wip refactoring structs to use span for read trait. Scanner still needs some work

* add span and list read funcs

* fixed scanner

* working state, tests passing

* update changelog
  • Loading branch information
thatstoasty authored Jun 20, 2024
1 parent fc0bebf commit c0d8b32
Show file tree
Hide file tree
Showing 39 changed files with 1,842 additions and 1,002 deletions.
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@

# Change Log

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased] - yyyy-mm-dd

## [0.0.2] - 2024-06-19

### Added

- UDP support in `net` package.
- `examples` package with `tcp` and `udp` examples using `Socket` and their respective `dial` and `listen` functions.
- Added `scan_runes` split function to `bufio.scan` module.
- Added `bufio.Scanner` examples to the `examples` directory.

### Removed

- `Listener`, `Dialer`, and `Conn` interfaces have been removed until Trait support improves. For now, call `listen_tcp/listen_udp` and `dial_tcp/dial_udp` functions directly.

### Changed

- Incrementally moving towards using `Span` for the `Reader` and `Writer` traits. Added an `_read` function to `Reader` and `_read_at` to `ReaderAt` traits to enable reading into `Span`. The usual implementation is the take a `List[UInt8]` but then to use `_read` and pass a `Span` constructed from the List.

## [0.0.1] - 2024-06-16

### Changed
Expand Down
Empty file added examples/__init__.mojo
Empty file.
Empty file added examples/scanner/__init__.mojo
Empty file.
33 changes: 33 additions & 0 deletions examples/scanner/scan_text.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from gojo.bytes import buffer
from gojo.bufio import Reader, Scanner, scan_words


fn print_words(owned text: String):
# Create a reader from a string buffer
var buf = buffer.new_buffer(text^)
var r = Reader(buf^)

# Create a scanner from the reader
var scanner = Scanner[split=scan_words](r^)

while scanner.scan():
print(scanner.current_token())


fn print_lines(owned text: String):
# Create a reader from a string buffer
var buf = buffer.new_buffer(text^)
var r = Reader(buf^)

# Create a scanner from the reader
var scanner = Scanner(r^)

while scanner.scan():
print(scanner.current_token())


fn main():
var text = String("Testing this string!")
var text2 = String("Testing\nthis\nstring!")
print_words(text^)
print_lines(text2^)
Empty file added examples/tcp/__init__.mojo
Empty file.
43 changes: 43 additions & 0 deletions examples/tcp/dial_client.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from gojo.net import Socket, HostPort, dial_tcp, TCPAddr
from gojo.syscall import SocketType
import gojo.io


fn main() raises:
# Create UDP Connection
alias message = String("dial")
alias host = "127.0.0.1"
alias port = 8081

for _ in range(10):
var connection = dial_tcp("tcp", host, port)
var bytes_written: Int
var err: Error
bytes_written, err = connection.write(
String("GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n").as_bytes()
)
if err:
raise err

if bytes_written == 0:
print("No bytes sent to peer.")
return

# Read the response from the connection
var response = List[UInt8](capacity=4096)
var bytes_read: Int = 0
bytes_read, err = connection.read(response)
if err and str(err) != io.EOF:
raise err

if bytes_read == 0:
print("No bytes received from peer.")
return

response.append(0)
print("Message received:", String(response^))

# Cleanup the connection
err = connection.close()
if err:
raise err
37 changes: 37 additions & 0 deletions examples/tcp/get_request.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from gojo.net import TCPAddr, get_ip_address, dial_tcp
from gojo.syscall import ProtocolFamily


fn main() raises:
# Connect to example.com on port 80 and send a GET request
var connection = dial_tcp("tcp", TCPAddr(get_ip_address("www.example.com"), 80))
var bytes_written: Int = 0
var err = Error()
bytes_written, err = connection.write(
String("GET / HTTP/1.1\r\nHost: www.example.com\r\nConnection: close\r\n\r\n").as_bytes()
)
if err:
raise err

if bytes_written == 0:
print("No bytes sent to peer.")
return

# Read the response from the connection
var response = List[UInt8](capacity=4096)
var bytes_read: Int = 0
bytes_read, err = connection.read(response)
if err:
raise err

if bytes_read == 0:
print("No bytes received from peer.")
return

response.append(0)
print(String(response^))

# Cleanup the connection
err = connection.close()
if err:
raise err
27 changes: 27 additions & 0 deletions examples/tcp/listener_server.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from gojo.net import TCPAddr, get_ip_address, listen_tcp, HostPort
import gojo.io


fn main() raises:
var listener = listen_tcp("udp", TCPAddr("127.0.0.1", 12000))

while True:
var connection = listener.accept()

# Read the contents of the message from the client.
var bytes = List[UInt8](capacity=4096)
var bytes_read: Int
var err: Error
bytes_read, err = connection.read(bytes)
if str(err) != io.EOF:
raise err

bytes.append(0)
var message = String(bytes^)
print("Message Received:", message)
message = message.upper()

# Send a response back to the client.
var bytes_sent: Int
bytes_sent, err = connection.write(message.as_bytes())
print("Message sent:", message, bytes_sent)
35 changes: 35 additions & 0 deletions examples/tcp/socket_client.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from gojo.net import Socket, HostPort
from gojo.syscall import SocketType
import gojo.io


fn main() raises:
# Create TCP Socket
var socket = Socket()
alias message = String("test")
alias host = "127.0.0.1"
alias port = 8082

# Bind client to port 8082
socket.bind(host, port)

# Send 10 test messages
var err = socket.connect(host, 8081)
if err:
raise err
var bytes_sent: Int
bytes_sent, err = socket.write(message.as_bytes())
print("Message sent:", message)

var bytes = List[UInt8](capacity=16)
var bytes_read: Int
bytes_read, err = socket.read(bytes)
if str(err) != io.EOF:
raise err

bytes.append(0)
var response = String(bytes^)
print("Message received:", response)

_ = socket.shutdown()
_ = socket.close()
40 changes: 40 additions & 0 deletions examples/tcp/socket_server.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from gojo.net import Socket, HostPort
from gojo.syscall import SocketOptions
import gojo.io


fn main() raises:
var socket = Socket()
socket.set_socket_option(SocketOptions.SO_REUSEADDR, 1)
alias host = "127.0.0.1"
alias port = 8081

# Bind server to port 8081
socket.bind(host, port)
socket.listen()
print("Listening on", socket.local_address_as_tcp())
while True:
# Accept connections from clients and serve them.
var connection = socket.accept()
print("Serving", connection.remote_address_as_tcp())

# Read the contents of the message from the client.
var bytes = List[UInt8](capacity=4096)
var bytes_read: Int
var err: Error
bytes_read, err = connection.read(bytes)
if str(err) != io.EOF:
raise err

bytes.append(0)
var message = String(bytes^)
print("Message Received:", message)
message = message.upper()

# Send a response back to the client.
var bytes_sent: Int
bytes_sent, err = connection.write(message.as_bytes())
print("Message sent:", message, bytes_sent)
err = connection.close()
if err:
raise err
Empty file added examples/udp/__init__.mojo
Empty file.
29 changes: 29 additions & 0 deletions examples/udp/dial_client.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from gojo.net import Socket, HostPort, dial_udp, UDPAddr
from gojo.syscall import SocketType
import gojo.io


fn main() raises:
# Create UDP Connection
alias message = String("dial")
alias host = "127.0.0.1"
alias port = 12000
var udp = dial_udp("udp", host, port)

# Send 10 test messages
for _ in range(10):
var bytes_sent: Int
var err: Error
bytes_sent, err = udp.write_to(message.as_bytes(), host, port)
print("Message sent:", message, bytes_sent)

var bytes = List[UInt8](capacity=16)
var bytes_received: Int
var remote: HostPort
bytes_received, remote, err = udp.read_from(bytes)
if str(err) != io.EOF:
raise err

bytes.append(0)
var response = String(bytes^)
print("Message received:", response)
23 changes: 23 additions & 0 deletions examples/udp/listener_server.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from gojo.net import UDPAddr, get_ip_address, listen_udp, HostPort
import gojo.io


fn main() raises:
var listener = listen_udp("udp", UDPAddr("127.0.0.1", 12000))

while True:
var dest = List[UInt8](capacity=16)
var bytes_read: Int
var remote: HostPort
var err: Error
bytes_read, remote, err = listener.read_from(dest)
if err:
raise err

dest.append(0)
var message = String(dest^)
print("Message received:", message)
message = message.upper()
var bytes_sent: Int
bytes_sent, err = listener.write_to(message.as_bytes(), UDPAddr(remote.host, remote.port))
print("Message sent:", message)
28 changes: 28 additions & 0 deletions examples/udp/socket_client.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from gojo.net import Socket, HostPort
from gojo.syscall import SocketType
import gojo.io


fn main() raises:
# Create UDP Socket
var socket = Socket(socket_type=SocketType.SOCK_DGRAM)
alias message = String("test")
alias host = "127.0.0.1"
alias port = 12000

# Send 10 test messages
for _ in range(10):
var bytes_sent: Int
var err: Error
bytes_sent, err = socket.send_to(message.as_bytes(), host, port)
print("Message sent:", message)

var bytes: List[UInt8]
var remote: HostPort
bytes, remote, err = socket.receive_from(1024)
if str(err) != io.EOF:
raise err

bytes.append(0)
var response = String(bytes^)
print("Message received:", response)
28 changes: 28 additions & 0 deletions examples/udp/socket_server.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from gojo.net import Socket, HostPort
from gojo.syscall import SocketType
import gojo.io


fn main() raises:
var socket = Socket(socket_type=SocketType.SOCK_DGRAM)
alias host = "127.0.0.1"
alias port = 12000

socket.bind(host, port)
print("Listening on", socket.local_address_as_udp())
while True:
var bytes: List[UInt8]
var remote: HostPort
var err: Error
bytes, remote, err = socket.receive_from(1024)
if str(err) != io.EOF:
raise err

bytes.append(0)
var message = String(bytes^)
print("Message Received:", message)
message = message.upper()

var bytes_sent: Int
bytes_sent, err = socket.send_to(message.as_bytes(), remote.host, remote.port)
print("Message sent:", message)
2 changes: 1 addition & 1 deletion gojo/bufio/__init__.mojo
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .bufio import Reader, Writer, ReadWriter
from .scan import Scanner, scan_words, scan_bytes, scan_lines
from .scan import Scanner, scan_words, scan_bytes, scan_lines, scan_runes
Loading

0 comments on commit c0d8b32

Please sign in to comment.