gemini://://gemini.dimakrasner.com/pico-w.gmi
View on Gemini
#

Gemini Capsule on Pico W

I received my Pico W long time ago but couldn't find the time to finish this.

I decided to do this in Python (using MicroPython) first, then translate to C and see how things can be improved.

It's very simple and very basic, without concurrency. Like my ESP32 setup, it uses Duck DNS. The key and the certificate are at /pyboard/{key,cert}.der and this is /pyboard/boot.py:

```
	import ussl
```
	import socket
```
	import network
```
	import _thread
```
	import machine
```
	import urequests
```
```
	SSID = 'AAA'
```
	PASSPHRASE = 'BBB'
```
	DOMAINS = 'CCC'
```
	TOKEN = 'DDD'
```
	PORT = 1965
```
```
	keyfile = open("key.der", "rb").read()
```
	certfile = open("cert.der", "rb").read()
```
	 
```
	def read_request(sc):
```
		buf = sc.read(len('gemini://a'))
```
		while not buf.endswith(b'\r') and len(buf) < 64:
```
			b = sc.read(1)
```
			buf += b
```
		if not buf.endswith(b'\r'):
```
			raise Exception('Truncated request')
```
```
		url = buf[:-1].decode('utf-8')
```
		_, _, _, path = url.split("/", 3)
```
		path = path.lstrip('/')
```
		print(url)
```
```
		if len(path) == 0 or path == '/':
```
			path = 'index.gmi'
```
		elif path == 'key.der' or path == 'cert.der' or path == 'main.py':
```
			sc.write(f'40 Forbidden\r\n')
```
			raise Exception(f"Forbidden path: {path}")
```
		
```
		return path
```
```
	def handle_request(c):
```
		try:
```
			sc = ussl.wrap_socket(c, server_side=True, key=keyfile, cert=certfile)
```
			try:
```
				path = read_request(sc)
```
```
				sc.write(f'20 text/gemini\r\n')
```
```
				with open(path, "rb") as f:
```
					while True:
```
						chunk = f.read(128)
```
						if len(chunk) == 0:
```
							break
```
						sc.write(chunk)
```
			finally:
```
				sc.close()
```
		finally:
```
			c.close()
```
```
	wlan = network.WLAN(network.STA_IF)
```
	wlan.active(True)
```
	wlan.connect(SSID, PASSPHRASE)
```
```
	s = socket.socket()
```
	s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
```
	s.bind(('0.0.0.0', PORT))
```
	s.listen(1)
```
	led = machine.Pin('LED', machine.Pin.OUT)
```
```
	print(f"Local address: {wlan.ifconfig()[0]}")
```
	print('Updating public address')
```
	urequests.get(f"https://www.duckdns.org/update?domains={DOMAINS}&token={TOKEN}")
```
```
	print('Ready')
```
	while True:
```
		try:
```
			print('Waiting for request')
```
			c, _ = s.accept()
```
		except Exception as e:
```
			print(e)
```
			continue
```
```
		try:
```
			print('Handling request')
```
			c.settimeout(10)
```
			led.value(1)
```
			try:
```
				handle_request(c)
```
			finally:
```
				led.value(0)
```
		except Exception as e:
```
			print(e)
```
			c.close()

It doesn't send close_notify, something I could fix in my ESP32 Gemini server written in C by forcing mbedtls_ssl_close_notify((mbedtls_ssl_context*)tls), although all other uses of mbedlts are wrapped nicely with the ESP-TLS API. I hope I can do something similar in the Pico without having to patch ussl and rebuild MicroPython.