127 lines
2.7 KiB
Go
127 lines
2.7 KiB
Go
package itcp
|
|
|
|
import (
|
|
"net"
|
|
"fmt"
|
|
"sync"
|
|
"io"
|
|
"context"
|
|
iroh "git.coopcloud.tech/decentral1se/iroh-go"
|
|
"gomod.cblgh.org/cerca/util/eout"
|
|
)
|
|
|
|
type ITCP struct {
|
|
LocalListener net.Listener
|
|
Endpoint *iroh.Endpoint
|
|
ch chan string
|
|
port int
|
|
conns *sync.Map
|
|
}
|
|
|
|
// create an iroh endpoint
|
|
func NewITCP(alpn, secretBytes []byte, port int, conns *sync.Map) *ITCP {
|
|
initLogger()
|
|
var t ITCP
|
|
t.port = port
|
|
t.ch = make(chan string)
|
|
t.conns = conns
|
|
|
|
preset := iroh.PresetN0()
|
|
opts := iroh.EndpointOptions{
|
|
Preset: &preset,
|
|
Alpns: &[][]byte{alpn},
|
|
}
|
|
|
|
// static endpoint key being set
|
|
if len(secretBytes) > 0 {
|
|
opts.SecretKey = &secretBytes
|
|
}
|
|
|
|
endpoint, err := iroh.EndpointBind(opts)
|
|
if err := iroh.As(err); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
endpoint.Online()
|
|
fmt.Printf("online as %s\n", endpoint.Id())
|
|
|
|
ticket, err := iroh.EndpointTicketFromAddr(endpoint.Addr())
|
|
eout.Check(err, "format ticket")
|
|
fmt.Println("\nticket:")
|
|
fmt.Println(ticket, "\n")
|
|
|
|
t.Endpoint = endpoint
|
|
return &t
|
|
}
|
|
|
|
func (t *ITCP) GetHost() string {
|
|
return fmt.Sprintf(":%d", t.port)
|
|
}
|
|
|
|
func (t *ITCP) Start(ctx context.Context) {
|
|
tcphost := t.GetHost()
|
|
var err error
|
|
log(fmt.Sprintf("setting up local listener on %s", tcphost))
|
|
t.LocalListener, err = net.Listen("tcp", tcphost)
|
|
eout.Check(err, "set up local listener")
|
|
|
|
go t.handleIncoming(tcphost)
|
|
}
|
|
|
|
// implements net.Listener
|
|
func (t *ITCP) Accept() (net.Conn, error) {
|
|
c, err := t.LocalListener.Accept()
|
|
// receive endpoint id from t.handleIncoming goroutine
|
|
endpointId := <-t.ch
|
|
t.conns.Store(c, endpointId)
|
|
return c, err
|
|
}
|
|
|
|
// implements net.Listener
|
|
func (t *ITCP) Close() error {
|
|
// TODO (2026-10-21)
|
|
return t.LocalListener.Close()
|
|
}
|
|
|
|
// implements net.Listener
|
|
func (t *ITCP) Addr() net.Addr {
|
|
return t.LocalListener.Addr()
|
|
}
|
|
|
|
func (t *ITCP) handleIncoming(tcphost string) {
|
|
for {
|
|
incoming := t.Endpoint.AcceptNext()
|
|
log("incoming")
|
|
accepting, err := (*incoming).Accept()
|
|
if err := iroh.As(err); err != nil {
|
|
eout.Check(err, "incoming.Accept")
|
|
}
|
|
log("accepted")
|
|
conn, err := accepting.Connect()
|
|
if err := iroh.As(err); err != nil {
|
|
eout.Check(err, "incoming.Connect")
|
|
}
|
|
log("connected")
|
|
stream, err := conn.AcceptBi()
|
|
if err := iroh.As(err); err != nil {
|
|
eout.Check(err, "incoming.AcceptBi")
|
|
panic(err)
|
|
}
|
|
log("bidi stream")
|
|
|
|
// send endpoint public key to be received by accept handler
|
|
go func(endpointId string) {
|
|
t.ch <- endpointId
|
|
}(conn.RemoteId().String())
|
|
|
|
pipe := iroh.NewPipe(stream)
|
|
|
|
log("pre dial")
|
|
dialedConn, err := net.Dial("tcp", tcphost)
|
|
eout.Check(err, "net.dial")
|
|
go io.Copy(dialedConn, pipe)
|
|
go io.Copy(pipe, dialedConn)
|
|
log("post dial")
|
|
}
|
|
}
|