mirror of
https://github.com/number571/blockchain.git
synced 2026-09-13 18:45:45 +05:00
131 lines
2.3 KiB
Go
131 lines
2.3 KiB
Go
package network
|
|
|
|
import (
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
"encoding/json"
|
|
)
|
|
|
|
type Package struct {
|
|
Option int
|
|
Data string
|
|
}
|
|
|
|
func Send(address string, pack *Package) *Package {
|
|
conn, err := net.Dial("tcp", address)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
conn.Write([]byte(SerializePackage(pack) + ENDBYTES))
|
|
var res = new(Package)
|
|
ch := make(chan bool)
|
|
go func() {
|
|
res = readPackage(conn)
|
|
ch <- true
|
|
}()
|
|
select {
|
|
case <-ch:
|
|
case <-time.After(WAITTIME * time.Second):
|
|
}
|
|
return res
|
|
}
|
|
|
|
func SerializePackage(pack *Package) string {
|
|
jsonData, err := json.MarshalIndent(*pack, "", "\t")
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return string(jsonData)
|
|
}
|
|
|
|
const (
|
|
ENDBYTES = "\000\005\007\001\001\007\005\000"
|
|
)
|
|
|
|
func readPackage(conn net.Conn) *Package {
|
|
var (
|
|
data string
|
|
size = uint64(0)
|
|
buffer = make([]byte, BUFFSIZE)
|
|
)
|
|
for {
|
|
length, err := conn.Read(buffer)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
size += uint64(length)
|
|
if size > DMAXSIZE {
|
|
return nil
|
|
}
|
|
data += string(buffer[:length])
|
|
if strings.Contains(data, ENDBYTES) {
|
|
data = strings.Split(data, ENDBYTES)[0]
|
|
break
|
|
}
|
|
}
|
|
return DeserializePackage(data)
|
|
}
|
|
|
|
const (
|
|
WAITTIME = 5 // seconds
|
|
DMAXSIZE = (2 << 20) // (2^20)*2 = 2MiB
|
|
BUFFSIZE = (4 << 10) // (2^10)*4 = 4KiB
|
|
)
|
|
|
|
func DeserializePackage(data string) *Package {
|
|
var pack Package
|
|
err := json.Unmarshal([]byte(data), &pack)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return &pack
|
|
}
|
|
|
|
func Listen(address string, handle func(Conn, *Package)) Listener {
|
|
splited := strings.Split(address, ":")
|
|
if len(splited) != 2 {
|
|
return nil
|
|
}
|
|
listener, err := net.Listen("tcp", "0.0.0.0:"+splited[1])
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
go serve(listener, handle)
|
|
return Listener(listener)
|
|
}
|
|
|
|
func serve(listener net.Listener, handle func(Conn, *Package)) {
|
|
defer listener.Close()
|
|
for {
|
|
conn, err := listener.Accept()
|
|
if err != nil {
|
|
break
|
|
}
|
|
go handleConn(conn, handle)
|
|
}
|
|
}
|
|
func handleConn(conn net.Conn, handle func(Conn, *Package)) {
|
|
defer conn.Close()
|
|
pack := readPackage(conn)
|
|
if pack == nil {
|
|
return
|
|
}
|
|
handle(Conn(conn), pack)
|
|
}
|
|
|
|
type Listener net.Listener
|
|
type Conn net.Conn
|
|
|
|
func Handle(option int, conn Conn, pack *Package, handle func(*Package) string) bool {
|
|
if pack.Option != option {
|
|
return false
|
|
}
|
|
conn.Write([]byte(SerializePackage(&Package{
|
|
Option: option,
|
|
Data: handle(pack),
|
|
}) + ENDBYTES))
|
|
return true
|
|
}
|
|
|