mirror of
https://github.com/eosswedenorg/eth-healthcheck
synced 2026-06-16 05:04:55 +02:00
Inital Commit
This commit is contained in:
commit
0d27205c7c
15 changed files with 472 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
build/
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 EOS Sw/eden
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
25
Makefile
Normal file
25
Makefile
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
GO = go
|
||||||
|
GOCCFLAGS = -v
|
||||||
|
GOLDFLAGS = -ldflags="-s -w"
|
||||||
|
PREFIX = /usr/local
|
||||||
|
|
||||||
|
PROGRAM_NAME=eth-healthcheck
|
||||||
|
SOURCES=src/cmd/main.go
|
||||||
|
|
||||||
|
all: build
|
||||||
|
build: build/$(PROGRAM_NAME)
|
||||||
|
|
||||||
|
build/$(PROGRAM_NAME) : $(SOURCES)
|
||||||
|
$(GO) build -o $@ $(GOCCFLAGS) $(GOLDFLAGS) $^
|
||||||
|
|
||||||
|
pkg_info :
|
||||||
|
echo PACKAGE_NAME=\"$(PROGRAM_NAME)\" "\n"\
|
||||||
|
PACKAGE_DESCRIPTION=\"HAproxy healthcheck program for Etherium nodes.\" "\n"\
|
||||||
|
PACKAGE_VERSION=\"0.1.0\" "\n"\
|
||||||
|
PACKAGE_PREFIX=\"$(PREFIX:/%=%)\" "\n"\
|
||||||
|
PACKAGE_PROGRAM=\"$(PROGRAM_NAME)\" > build/pkg_info
|
||||||
|
|
||||||
|
package : build pkg_info
|
||||||
|
|
||||||
|
package_deb: package
|
||||||
|
./scripts/pkg.sh deb $(realpath build)
|
||||||
79
compile.sh
Executable file
79
compile.sh
Executable file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SYSTEMS=( windows linux freebsd )
|
||||||
|
|
||||||
|
ARCHS=( 386 amd64 amd64p32 arm arm64 ppc ppc64 )
|
||||||
|
|
||||||
|
function usage() {
|
||||||
|
echo "Usage: ${0##*/} [ -h|--help ] [ --target <system> ] [ -a|--arch <arch> ] [ -p|--package ]"
|
||||||
|
echo ""
|
||||||
|
echo " Valid systems:"
|
||||||
|
for i in "${SYSTEMS[@]}"; do
|
||||||
|
echo " * ${i}"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo " Valid architectures:"
|
||||||
|
for i in "${ARCHS[@]}"; do
|
||||||
|
echo " * ${i}"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
options=$(getopt -n "${0##*/}" -o "ht:a:p" -l "help,target:,arch:,package" -- "$@")
|
||||||
|
|
||||||
|
[ $? -eq 0 ] || usage
|
||||||
|
|
||||||
|
eval set -- "$options"
|
||||||
|
|
||||||
|
MAKE_TARGET="all"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
-p|--package)
|
||||||
|
MAKE_TARGET="package_deb"
|
||||||
|
;;
|
||||||
|
-t|--target)
|
||||||
|
shift
|
||||||
|
REGEX=$(echo "${SYSTEMS[@]}" | sed 's/[[:space:]]/|/g')
|
||||||
|
[[ ! "$1" =~ ^($REGEX)$ ]] && {
|
||||||
|
echo "Incorrect system '$1' provided"
|
||||||
|
usage
|
||||||
|
}
|
||||||
|
export GOOS=$1
|
||||||
|
;;
|
||||||
|
-a|--arch)
|
||||||
|
shift
|
||||||
|
REGEX=$(echo "${ARCHS[@]}" | sed 's/[[:space:]]/|/g')
|
||||||
|
[[ ! "$1" =~ ^($REGEX)$ ]] && {
|
||||||
|
echo "Incorrect architecture '$1' provided"
|
||||||
|
usage
|
||||||
|
}
|
||||||
|
export GOARCH=$1
|
||||||
|
;;
|
||||||
|
-h|--help) usage ;;
|
||||||
|
--) shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
MESSAGE=""
|
||||||
|
if [ ! -z "${GOOS}" ]; then
|
||||||
|
# Hack to select the right package :)
|
||||||
|
if [ "${MAKE_TARGET}" == "package_deb" ] && [ "${GOOS}" == "freebsd" ]; then
|
||||||
|
MAKE_TARGET="package_freebsd"
|
||||||
|
fi
|
||||||
|
MESSAGE="[\e[34m::\e[0m] Crosscompiling for: ${GOOS}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "${GOARCH}" ]; then
|
||||||
|
MESSAGE="${MESSAGE} (${GOARCH})"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
[ ! -z "${MESSAGE}" ] && echo -e "" $MESSAGE
|
||||||
|
|
||||||
|
make -B ${MAKE_TARGET}
|
||||||
17
go.mod
Normal file
17
go.mod
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
module eosswedenorg/eth-healthcheck
|
||||||
|
|
||||||
|
go 1.14
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-stack/stack v1.8.0
|
||||||
|
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac
|
||||||
|
github.com/mattn/go-colorable v0.1.8
|
||||||
|
github.com/mattn/go-isatty v0.0.13
|
||||||
|
github.com/onrik/ethrpc v1.0.0
|
||||||
|
github.com/pborman/getopt/v2 v2.1.0
|
||||||
|
internal/haproxy v1.0.0
|
||||||
|
internal/tcp_server v1.0.0
|
||||||
|
)
|
||||||
|
|
||||||
|
replace internal/haproxy => ./src/haproxy
|
||||||
|
replace internal/tcp_server => ./src/tcp_server
|
||||||
16
go.sum
Normal file
16
go.sum
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac h1:n1DqxAo4oWPMvH1+v+DLYlMCecgumhhgnxAPdqDIFHI=
|
||||||
|
github.com/inconshreveable/log15 v0.0.0-20201112154412-8562bdadbbac/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
|
||||||
|
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||||
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||||
|
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/onrik/ethrpc v1.0.0 h1:caG0U/Y1op32mntqmDnwvzue4Tg37cSA2EU8PMIMSjM=
|
||||||
|
github.com/onrik/ethrpc v1.0.0/go.mod h1:RoqOlDiBBs1qYamkcYhxMgkPijxu5R8t55mgUiy4le8=
|
||||||
|
github.com/pborman/getopt/v2 v2.1.0 h1:eNfR+r+dWLdWmV8g5OlpyrTYHkhVNxHBdN2cCrJmOEA=
|
||||||
|
github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLtsOpwKIKd0=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
36
scripts/pkg.sh
Executable file
36
scripts/pkg.sh
Executable file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
############################
|
||||||
|
# Exported variables. #
|
||||||
|
############################
|
||||||
|
|
||||||
|
export BASE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
|
||||||
|
if [ $# -lt 2 ]; then
|
||||||
|
echo "$0 <pkg_type> <build_dir>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PKG_TYPE=$1
|
||||||
|
BUILD_DIR=$2
|
||||||
|
|
||||||
|
PKG_SCRIPT="${BASE_DIR}/pkg_${PKG_TYPE}.sh"
|
||||||
|
|
||||||
|
# Check and call script
|
||||||
|
if [ ! -x $PKG_SCRIPT ]; then
|
||||||
|
echo "$PKG_SCRIPT not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Info
|
||||||
|
set -o allexport
|
||||||
|
source ${BUILD_DIR}/pkg_info
|
||||||
|
set +o allexport
|
||||||
|
|
||||||
|
# Directories.
|
||||||
|
export PACKAGE_BINDIR=${PACKAGE_PREFIX}/bin
|
||||||
|
export PACKAGE_SHAREDIR=${PACKAGE_PREFIX}/share/${PACKAGE_NAME}
|
||||||
|
export PACKAGE_TMPDIR="${BUILD_DIR}/pkg_${PKG_TYPE}"
|
||||||
|
export BUILD_DIR
|
||||||
|
|
||||||
|
$PKG_SCRIPT
|
||||||
46
scripts/pkg_deb.sh
Executable file
46
scripts/pkg_deb.sh
Executable file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
PACKAGE_ARCH=amd64
|
||||||
|
|
||||||
|
if [[ -f /etc/upstream-release/lsb-release ]]; then
|
||||||
|
source /etc/upstream-release/lsb-release
|
||||||
|
elif [[ -f /etc/lsb-release ]]; then
|
||||||
|
source /etc/lsb-release
|
||||||
|
else
|
||||||
|
echo "ERROR: could not determine debian release."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DISTRIB_ID=$(echo $DISTRIB_ID | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
|
# Default to 1 if no release is set.
|
||||||
|
if [[ -z $RELEASE ]]; then
|
||||||
|
RELEASE="1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
PACKAGE_FULLNAME="${PACKAGE_NAME}_${PACKAGE_VERSION}-${RELEASE}-${DISTRIB_ID}-${DISTRIB_RELEASE}_${PACKAGE_ARCH}"
|
||||||
|
|
||||||
|
rm -fr ${PACKAGE_TMPDIR}
|
||||||
|
|
||||||
|
# Create debian files.
|
||||||
|
mkdir -p ${PACKAGE_TMPDIR}/DEBIAN
|
||||||
|
echo "Package: ${PACKAGE_NAME}
|
||||||
|
Version: ${PACKAGE_VERSION}-${RELEASE}
|
||||||
|
Section: introspection
|
||||||
|
Priority: optional
|
||||||
|
Architecture: ${PACKAGE_ARCH}
|
||||||
|
Homepage: https://github.com/eosswedenorg/eth-healthcheck
|
||||||
|
Maintainer: Henrik Hautakoski <henrik@eossweden.org>
|
||||||
|
Description: ${PACKAGE_DESCRIPTION}" &> ${PACKAGE_TMPDIR}/DEBIAN/control
|
||||||
|
|
||||||
|
cat ${PACKAGE_TMPDIR}/DEBIAN/control
|
||||||
|
|
||||||
|
# Copy program
|
||||||
|
mkdir -p ${PACKAGE_TMPDIR}/${PACKAGE_BINDIR}
|
||||||
|
cp ${BUILD_DIR}/${PACKAGE_PROGRAM} ${PACKAGE_TMPDIR}/${PACKAGE_BINDIR}/${PACKAGE_NAME}
|
||||||
|
|
||||||
|
# Copy files.
|
||||||
|
mkdir -p ${PACKAGE_TMPDIR}/${PACKAGE_SHAREDIR}
|
||||||
|
cp ${BASE_DIR}/../LICENSE ${PACKAGE_TMPDIR}/${PACKAGE_SHAREDIR}
|
||||||
|
|
||||||
|
fakeroot dpkg-deb --build ${PACKAGE_TMPDIR} ${BUILD_DIR}/${PACKAGE_FULLNAME}.deb
|
||||||
91
src/cmd/main.go
Normal file
91
src/cmd/main.go
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
log "github.com/inconshreveable/log15"
|
||||||
|
"github.com/pborman/getopt/v2"
|
||||||
|
"github.com/onrik/ethrpc"
|
||||||
|
"internal/haproxy"
|
||||||
|
"internal/tcp_server"
|
||||||
|
)
|
||||||
|
|
||||||
|
var logger log.Logger
|
||||||
|
|
||||||
|
func onConnect(c *tcp_server.Client) {
|
||||||
|
logger.Info("Client connected", "addr", c.Addr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func onTcpMessage(c *tcp_server.Client, message string) {
|
||||||
|
|
||||||
|
status := haproxy.HealthCheckDown
|
||||||
|
client := ethrpc.New(strings.TrimSpace(message))
|
||||||
|
|
||||||
|
resp, err := client.EthSyncing()
|
||||||
|
if err == nil {
|
||||||
|
if resp.IsSyncing == false {
|
||||||
|
status = haproxy.HealthCheckUp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.Warn(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Node status", "status", status)
|
||||||
|
|
||||||
|
// Report status to HAproxy
|
||||||
|
c.WriteString(fmt.Sprintln(status))
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func onDisconnect(c *tcp_server.Client, err error) {
|
||||||
|
if err == nil {
|
||||||
|
logger.Info("Client disconnected", "addr", c.Addr.String())
|
||||||
|
} else {
|
||||||
|
logger.Warn("Client disconnected", "addr", c.Addr.String(), "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func argv_listen_addr() string {
|
||||||
|
|
||||||
|
var addr string
|
||||||
|
|
||||||
|
argv := getopt.Args()
|
||||||
|
if len(argv) > 0 {
|
||||||
|
addr = argv[0]
|
||||||
|
} else {
|
||||||
|
addr = "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
addr += ":"
|
||||||
|
if len(argv) > 1 {
|
||||||
|
addr += argv[1]
|
||||||
|
} else {
|
||||||
|
addr += "1301"
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
logger = log.New()
|
||||||
|
|
||||||
|
getopt.Parse()
|
||||||
|
|
||||||
|
addr := argv_listen_addr()
|
||||||
|
server := tcp_server.New(argv_listen_addr())
|
||||||
|
|
||||||
|
logger.Info(fmt.Sprintf("Listening on: %s", addr))
|
||||||
|
|
||||||
|
// TCP Client sends message.
|
||||||
|
server.OnConnect(onConnect)
|
||||||
|
server.OnMessage(onTcpMessage)
|
||||||
|
server.OnDisconnect(onDisconnect)
|
||||||
|
|
||||||
|
err := server.Listen()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/haproxy/go.mod
Normal file
3
src/haproxy/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module internal/haproxy
|
||||||
|
|
||||||
|
go 1.14
|
||||||
15
src/haproxy/types.go
Normal file
15
src/haproxy/types.go
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
package haproxy
|
||||||
|
|
||||||
|
// All supported health check values for HAproxy.
|
||||||
|
// See https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#5.2-agent-check
|
||||||
|
type HealthCheckStatus string
|
||||||
|
const (
|
||||||
|
HealthCheckUp = "up"
|
||||||
|
HealthCheckDown = "down"
|
||||||
|
HealthCheckMaint = "maint"
|
||||||
|
HealthCheckReady = "ready"
|
||||||
|
HealthCheckDrain = "drain"
|
||||||
|
HealthCheckFailed = "failed"
|
||||||
|
HealthCheckStopped = "Stopped"
|
||||||
|
)
|
||||||
44
src/tcp_server/client.go
Normal file
44
src/tcp_server/client.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
package tcp_server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read client messages.
|
||||||
|
func (c *Client) read() {
|
||||||
|
reader := bufio.NewReader(c.conn)
|
||||||
|
for {
|
||||||
|
message, err := reader.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
c.conn.Close()
|
||||||
|
c.Server.onDisconnect(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Server.onMessage(c, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write string to client.
|
||||||
|
func (c *Client) WriteString(message string) error {
|
||||||
|
return c.Write([]byte(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write bytes to client
|
||||||
|
func (c *Client) Write(b []byte) error {
|
||||||
|
_, err := c.conn.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
c.conn.Close()
|
||||||
|
c.Server.onDisconnect(c, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Conn() net.Conn {
|
||||||
|
return c.conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) Close() error {
|
||||||
|
return c.conn.Close()
|
||||||
|
}
|
||||||
3
src/tcp_server/go.mod
Normal file
3
src/tcp_server/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module internal/tcp_server
|
||||||
|
|
||||||
|
go 1.14
|
||||||
56
src/tcp_server/server.go
Normal file
56
src/tcp_server/server.go
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
package tcp_server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(address string) *server {
|
||||||
|
|
||||||
|
server := &server{
|
||||||
|
address: address,
|
||||||
|
}
|
||||||
|
|
||||||
|
server.OnConnect(func(c *Client) {})
|
||||||
|
server.OnMessage(func(c *Client, message string) {})
|
||||||
|
server.OnDisconnect(func(c *Client, err error) {})
|
||||||
|
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when a client connects
|
||||||
|
func (s *server) OnConnect(callback func(c *Client)) {
|
||||||
|
s.onConnect = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called the server gets a message from a client.
|
||||||
|
func (s *server) OnMessage(callback func(c *Client, message string)) {
|
||||||
|
s.onMessage = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when a connection is closed.
|
||||||
|
func (s *server) OnDisconnect(callback func(c *Client, err error)) {
|
||||||
|
s.onDisconnect = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) Listen() error {
|
||||||
|
|
||||||
|
sock, err := net.Listen("tcp", s.address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer sock.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, _ := sock.Accept()
|
||||||
|
c := &Client{
|
||||||
|
conn: conn,
|
||||||
|
Server: s,
|
||||||
|
Addr: conn.RemoteAddr(),
|
||||||
|
}
|
||||||
|
s.onConnect(c)
|
||||||
|
go c.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
19
src/tcp_server/types.go
Normal file
19
src/tcp_server/types.go
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
package tcp_server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
conn net.Conn
|
||||||
|
Addr net.Addr
|
||||||
|
Server *server
|
||||||
|
}
|
||||||
|
|
||||||
|
type server struct {
|
||||||
|
address string
|
||||||
|
onConnect func(c *Client)
|
||||||
|
onDisconnect func(c *Client, err error)
|
||||||
|
onMessage func(c *Client, message string)
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue