Files
llgo/x/io/io.go

128 lines
3.4 KiB
Go
Raw Normal View History

2024-09-04 17:08:08 +08:00
//go:build llgo
// +build llgo
2024-07-22 19:34:49 +08:00
/*
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io
import (
2024-09-03 15:58:34 +08:00
"unsafe"
2024-07-22 19:34:49 +08:00
_ "unsafe"
2024-09-03 15:58:34 +08:00
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/libuv"
"github.com/goplus/llgo/c/net"
"github.com/goplus/llgo/x/async"
"github.com/goplus/llgo/x/cbind"
"github.com/goplus/llgo/x/tuple"
2024-07-22 19:34:49 +08:00
)
2024-09-03 15:58:34 +08:00
type Tcp struct {
2024-09-04 17:08:08 +08:00
tcp libuv.Tcp
2024-07-22 19:34:49 +08:00
}
2024-09-03 15:58:34 +08:00
type libuvError libuv.Errno
2024-07-22 19:34:49 +08:00
2024-09-03 15:58:34 +08:00
func (e libuvError) Error() string {
s := libuv.Strerror(libuv.Errno(e))
return c.GoString(s, c.Strlen(s))
2024-07-24 01:01:09 +08:00
}
2024-09-03 15:58:34 +08:00
func NewTcp() *Tcp {
2024-09-04 17:08:08 +08:00
t := &Tcp{}
libuv.InitTcp(async.Exec().L, &t.tcp)
2024-09-03 15:58:34 +08:00
return t
2024-07-22 19:34:49 +08:00
}
2024-09-03 15:58:34 +08:00
func (t *Tcp) Bind(addr *net.SockAddr, flags uint) error {
if res := t.tcp.Bind(addr, c.Uint(flags)); res != 0 {
return libuvError(res)
}
2024-07-23 17:02:40 +08:00
return nil
}
2024-09-04 17:08:08 +08:00
func (t *Tcp) Listen(backlog int, cb func(server *libuv.Stream, status c.Int)) error {
if res := (*libuv.Stream)(&t.tcp).Listen(c.Int(backlog), cb); res != 0 {
2024-09-03 15:58:34 +08:00
return libuvError(res)
}
2024-07-23 15:58:37 +08:00
return nil
}
2024-07-22 19:34:49 +08:00
2024-09-03 15:58:34 +08:00
func (t *Tcp) Accept() (client *Tcp, err error) {
2024-09-04 17:08:08 +08:00
tcp := &Tcp{}
if res := libuv.InitTcp(async.Exec().L, &tcp.tcp); res != 0 {
2024-09-03 15:58:34 +08:00
return nil, libuvError(res)
}
2024-09-04 17:08:08 +08:00
if res := (*libuv.Stream)(&t.tcp).Accept((*libuv.Stream)(&tcp.tcp)); res != 0 {
2024-09-03 15:58:34 +08:00
return nil, libuvError(res)
}
2024-09-04 17:08:08 +08:00
return tcp, nil
2024-09-03 15:58:34 +08:00
}
func Connect(addr *net.SockAddr) async.IO[tuple.Tuple2[*Tcp, error]] {
return async.Async(func(resolve func(tuple.Tuple2[*Tcp, error])) {
2024-09-04 17:08:08 +08:00
tcp := &Tcp{}
if res := libuv.InitTcp(async.Exec().L, &tcp.tcp); res != 0 {
2024-09-03 15:58:34 +08:00
resolve(tuple.T2[*Tcp, error]((*Tcp)(nil), libuvError(res)))
return
}
2024-09-04 17:08:08 +08:00
req, _ := cbind.Bind1[libuv.Connect](func(status c.Int) {
2024-09-03 15:58:34 +08:00
if status != 0 {
resolve(tuple.T2[*Tcp, error]((*Tcp)(nil), libuvError(libuv.Errno(status))))
}
})
2024-09-04 17:08:08 +08:00
if res := libuv.TcpConnect(req, &tcp.tcp, addr, cbind.Callback1[libuv.Connect, c.Int]); res != 0 {
2024-09-03 15:58:34 +08:00
resolve(tuple.T2[*Tcp, error]((*Tcp)(nil), libuvError(res)))
}
2024-09-04 17:08:08 +08:00
resolve(tuple.T2[*Tcp, error](tcp, nil))
2024-09-03 15:58:34 +08:00
})
2024-07-24 01:01:09 +08:00
}
2024-09-03 15:58:34 +08:00
func allocBuffer(handle *libuv.Handle, suggestedSize uintptr, buf *libuv.Buf) {
buf.Base = (*c.Char)(c.Malloc(suggestedSize))
buf.Len = suggestedSize
2024-07-24 01:01:09 +08:00
}
2024-09-03 15:58:34 +08:00
func (t *Tcp) Read() async.IO[tuple.Tuple2[[]byte, error]] {
return func(ctx *async.AsyncContext) async.Future[tuple.Tuple2[[]byte, error]] {
var result tuple.Tuple2[[]byte, error]
var done bool
2024-09-04 17:08:08 +08:00
tcp := (*libuv.Stream)(&t.tcp)
tcp.StartRead(allocBuffer, func(client *libuv.Stream, nread c.Long, buf *libuv.Buf) {
2024-09-03 15:58:34 +08:00
if nread > 0 {
2024-09-04 17:08:08 +08:00
result = tuple.T2[[]byte, error](cbind.GoBytes(buf.Base, int(nread)), nil)
2024-09-03 15:58:34 +08:00
} else if nread < 0 {
result = tuple.T2[[]byte, error](nil, libuvError(libuv.Errno(nread)))
} else {
result = tuple.T2[[]byte, error](nil, nil)
}
done = true
ctx.Complete()
2024-07-24 01:01:09 +08:00
})
2024-09-03 15:58:34 +08:00
return func() tuple.Tuple2[[]byte, error] {
if !done {
panic("Tcp.Read: Future accessed before completion")
}
return result
}
2024-07-24 01:01:09 +08:00
}
}
2024-09-04 17:08:08 +08:00
func (t *Tcp) Close() {
(*libuv.Handle)(unsafe.Pointer(&t.tcp)).Close(nil)
2024-07-24 01:01:09 +08:00
}