From 0f8e406da4e3510047819590678c316e0921cd9c Mon Sep 17 00:00:00 2001 From: zhangsz Date: Thu, 26 Jun 2025 10:41:21 +0800 Subject: [PATCH] init from svn --- Makefile | 52 + config/ac.yaml | 2 + scripts/ac.service | 11 + scripts/control | 10 + scripts/postinst | 15 + scripts/prerm | 7 + src/cmd/main.go | 49 + src/go.mod | 28 + src/go.sum | 53 + src/internal/capwap/handler.go | 17 + src/internal/capwap/service/service.go | 60 + src/internal/context/context.go | 74 + .../grpc_client/dhcpServer/dhcp_server.pb.go | 189 ++ .../grpc_client/dhcpServer/dhcp_server.proto | 18 + .../dhcpServer/dhcp_server_grpc.pb.go | 125 ++ src/internal/grpc_client/grpc_client.go | 38 + src/internal/logger/logger.go | 64 + src/internal/mqtt/message/message.pb.go | 1646 +++++++++++++++++ src/internal/mqtt/message/message.proto | 190 ++ src/internal/mqtt/server.go | 222 +++ src/internal/telnet/handler.go | 147 ++ src/internal/telnet/tcp.go | 100 + src/internal/version/version.go | 44 + src/pkg/app/app.go | 16 + src/pkg/factory/config.go | 71 + src/pkg/factory/factory.go | 48 + src/pkg/service/init.go | 129 ++ 27 files changed, 3425 insertions(+) create mode 100755 Makefile create mode 100755 config/ac.yaml create mode 100755 scripts/ac.service create mode 100644 scripts/control create mode 100755 scripts/postinst create mode 100755 scripts/prerm create mode 100644 src/cmd/main.go create mode 100644 src/go.mod create mode 100644 src/go.sum create mode 100644 src/internal/capwap/handler.go create mode 100644 src/internal/capwap/service/service.go create mode 100644 src/internal/context/context.go create mode 100644 src/internal/grpc_client/dhcpServer/dhcp_server.pb.go create mode 100644 src/internal/grpc_client/dhcpServer/dhcp_server.proto create mode 100644 src/internal/grpc_client/dhcpServer/dhcp_server_grpc.pb.go create mode 100644 src/internal/grpc_client/grpc_client.go create mode 100644 src/internal/logger/logger.go create mode 100644 src/internal/mqtt/message/message.pb.go create mode 100644 src/internal/mqtt/message/message.proto create mode 100644 src/internal/mqtt/server.go create mode 100755 src/internal/telnet/handler.go create mode 100755 src/internal/telnet/tcp.go create mode 100644 src/internal/version/version.go create mode 100644 src/pkg/app/app.go create mode 100644 src/pkg/factory/config.go create mode 100644 src/pkg/factory/factory.go create mode 100644 src/pkg/service/init.go diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..3396a33 --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +GO_BIN_PATH = bin +GO_SRC_PATH = src +ROOT_PATH = $(shell pwd) + +GO_NF = ac + +GO_FILES = $(shell find $(GO_SRC_PATH)/$(%) -name "*.go" ! -name "*_test.go") + +VERSION = 1.2408.0 +COMMIT_HASH = $(shell git log -1 --format=%h) +COMMIT_TIME = $(shell git log --pretty="@%at" -1 | xargs date -u +"%Y-%m-%d %H:%M:%SZ" -d) +LDFLAGS = -X 'ac/internal/version.VERSION=$(VERSION)' \ + -X 'ac/internal/version.COMMIT_HASH=$(COMMIT_HASH)' \ + -X 'ac/internal/version.COMMIT_TIME=$(COMMIT_TIME)' + +.PHONY: $(GO_NF) clean + +.DEFAULT_GOAL: $(GO_NF) + +all: $(GO_NF) + +debug: GCFLAGS += -N -l +debug: all + +$(GO_NF): % : $(GO_BIN_PATH)/% + +$(GO_BIN_PATH)/%: $(GO_FILES) +# $(@F): The file-within-directory part of the file name of the target. + @echo "Start building $(@F)...." + cd $(GO_SRC_PATH)/cmd && \ + go build -gcflags "$(GCFLAGS)" -ldflags "$(LDFLAGS)" -o $(ROOT_PATH)/$@ main.go + +vpath %.go $(addprefix $(GO_SRC_PATH)/, $(GO_NF)) + +deb: + test -d debian && rm -rf debian/* || mkdir debian + mkdir -p debian/DEBIAN + mkdir -p debian/usr/local/bin + mkdir -p debian/usr/local/etc/ac/default + mkdir -p debian/lib/systemd/system + cp $(GO_BIN_PATH)/$(GO_NF) debian/usr/local/bin + cp config/ac.yaml debian/usr/local/etc/ac/default + cp scripts/ac.service debian/lib/systemd/system + cp scripts/postinst debian/DEBIAN + cp scripts/prerm debian/DEBIAN + cp scripts/control debian/DEBIAN + fakeroot dpkg-deb --build debian + mv debian.deb debian/ac-r$(VERSION)-ub22.deb + +clean: + rm -rf $(addprefix $(GO_BIN_PATH)/, $(GO_NF)) + diff --git a/config/ac.yaml b/config/ac.yaml new file mode 100755 index 0000000..1cfa09e --- /dev/null +++ b/config/ac.yaml @@ -0,0 +1,2 @@ +debugLevel: trace +capwapAddr: 192.168.10.158 diff --git a/scripts/ac.service b/scripts/ac.service new file mode 100755 index 0000000..d5a64bc --- /dev/null +++ b/scripts/ac.service @@ -0,0 +1,11 @@ +[Service] +Type=idle +Environment=GOTRACEBACK=crash +ExecStart=/usr/local/bin/ac +Restart=always +RestartSec=1 +StartLimitInterval=0 +StandardOutput=null + +[Install] +WantedBy=multi-user.target diff --git a/scripts/control b/scripts/control new file mode 100644 index 0000000..5a5cec6 --- /dev/null +++ b/scripts/control @@ -0,0 +1,10 @@ +Package: ac +Version: 2.2409.0 +Section: net +Priority: optional +Architecture: amd64 +Essential: no +Depends: +Conflicts: ac +Maintainer: AC maintainer +Description: WLAN Software diff --git a/scripts/postinst b/scripts/postinst new file mode 100755 index 0000000..c7106c2 --- /dev/null +++ b/scripts/postinst @@ -0,0 +1,15 @@ +#! /bin/bash + +service_name=ac + +test ! -f /usr/local/etc/ac/ac.yaml && cp -f /usr/local/etc/ac/default/ac.yaml /usr/local/etc/ac + +if test -x /sbin/ldconfig +then + /sbin/ldconfig +else + echo Cannot run /sbin/ldconfig +fi + +systemctl enable $service_name + diff --git a/scripts/prerm b/scripts/prerm new file mode 100755 index 0000000..16ee390 --- /dev/null +++ b/scripts/prerm @@ -0,0 +1,7 @@ +#! /bin/bash + +# Commands to be run before uninstall of the package + +service_name=ac + +systemctl disable $service_name diff --git a/src/cmd/main.go b/src/cmd/main.go new file mode 100644 index 0000000..fd00518 --- /dev/null +++ b/src/cmd/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "context" + "os" + "os/signal" + "runtime/debug" + "syscall" + + "ac/internal/logger" + "ac/internal/version" + "ac/pkg/factory" + "ac/pkg/service" +) + +func main() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.MainLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + + logger.MainLog.Infoln("AC version: ", version.GetVersionAndHash()) + + ctx, cancel := context.WithCancel(context.Background()) + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) + + go func() { + <-sigCh // Wait for interrupt signal to gracefully shutdown + cancel() // Notify each goroutine and wait them stopped + }() + + cfg, err := factory.ReadConfig() + if err != nil { + logger.MainLog.Errorf("AC Run error: %v\n", err) + return + } + factory.AcConfig = cfg + + ac, err := service.NewApp(ctx, cfg) + if err != nil { + logger.MainLog.Errorf("AC Run error: %v\n", err) + return + } + + ac.Start() +} diff --git a/src/go.mod b/src/go.mod new file mode 100644 index 0000000..e18fe1a --- /dev/null +++ b/src/go.mod @@ -0,0 +1,28 @@ +module ac + +go 1.23.3 + +require ( + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 + github.com/davecgh/go-spew v1.1.1 + github.com/golang/protobuf v1.5.4 + github.com/mochi-mqtt/server/v2 v2.6.6 + github.com/natefinch/lumberjack v2.0.0+incompatible + github.com/sirupsen/logrus v1.9.3 + github.com/tim-ywliu/nested-logrus-formatter v1.3.2 + google.golang.org/grpc v1.68.0 + google.golang.org/protobuf v1.35.1 + gopkg.in/yaml.v2 v2.4.0 +) + +require ( + github.com/BurntSushi/toml v1.4.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/rs/xid v1.4.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/src/go.sum b/src/go.sum new file mode 100644 index 0000000..a4120e4 --- /dev/null +++ b/src/go.sum @@ -0,0 +1,53 @@ +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= +github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/mochi-mqtt/server/v2 v2.6.6 h1:FmL5ebeIIA+AKo/nX0DF8Yc2MMWFLQCwh3FZBEmg6dQ= +github.com/mochi-mqtt/server/v2 v2.6.6/go.mod h1:TqztjKGO0/ArOjJt9x9idk0kqPT3CVN8Pb+l+PS5Gdo= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tim-ywliu/nested-logrus-formatter v1.3.2 h1:jugNJ2/CNCI79SxOJCOhwUHeN3O7/7/bj+ZRGOFlCSw= +github.com/tim-ywliu/nested-logrus-formatter v1.3.2/go.mod h1:oGPmcxZB65j9Wo7mCnQKSrKEJtVDqyjD666SGmyStXI= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/src/internal/capwap/handler.go b/src/internal/capwap/handler.go new file mode 100644 index 0000000..e194757 --- /dev/null +++ b/src/internal/capwap/handler.go @@ -0,0 +1,17 @@ +package capwap + +import ( + "net" + + capwap_service "ac/internal/capwap/service" + "ac/internal/logger" +) + +func HandleMessage(peerAddr net.Addr, msg []byte) { + if len(msg) > 0 { + discoverResponse := [...]byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x0f, 0xaa, 0x92, 0xab, 0x5a, 0x4b, 0x31, 0x30, 0x35, 0x30, 0x46, 0x30, 0x32, 0x34, 0x38, 0x31, 0x33, 0x30, 0x30, 0x30, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x8c, 0xbf, 0x64, 0xb1, 0x46, 0xd1, 0x64, 0xcf, 0x88, 0x6d, 0x28, 0x47, 0x12, 0xa1, 0x75, 0xdb, 0xbe, 0x1d, 0x35, 0x0b, 0xfa, 0xa6, 0xa7, 0x2c, 0x36, 0x89, 0x27, 0x7f, 0x98, 0xff, 0xa6} + if _, err := capwap_service.SendMsg(peerAddr, discoverResponse[:]); err != nil { + logger.CapwapLog.Errorf("Capwap send Discovery Response error : %s", err) + } + } +} diff --git a/src/internal/capwap/service/service.go b/src/internal/capwap/service/service.go new file mode 100644 index 0000000..788b402 --- /dev/null +++ b/src/internal/capwap/service/service.go @@ -0,0 +1,60 @@ +package service + +import ( + "encoding/hex" + "net" + + "ac/internal/logger" +) + +type Handler func(addr net.Addr, msg []byte) + +var pktConn net.PacketConn + +func Run(address string, msgHandler Handler) { + var err error + laddr, err := net.ResolveUDPAddr("udp", "["+address+"]:5246") + if err != nil { + logger.CapwapLog.Println(err) + return + } + + // setup underlying connection first. + // not using net.Dial, as it binds src/dst IP:Port, which makes it harder to + // handle multiple connections with a Conn. + pktConn, err = net.ListenPacket(laddr.Network(), laddr.String()) + if err != nil { + return + } + + go func() { + for { + buf := make([]byte, 4096) + + n, addr, err := pktConn.ReadFrom(buf) + if err != nil { + return + } + + logger.CapwapLog.Tracef("Read %d bytes", n) + logger.CapwapLog.Tracef("Packet content:\n%+v", hex.Dump(buf[:n])) + + msgHandler(addr, buf[:n]) + } + }() +} + +// SendMsg - used to send out message to UDP connection +func SendMsg(raddr net.Addr, msg []byte) (int, error) { + if pktConn == nil || raddr == nil { + logger.CapwapLog.Warn("SendMsg failed.") + return 0, nil + } + return pktConn.WriteTo(msg, raddr) +} + +func Stop() { + if pktConn != nil { + pktConn.Close() + } +} diff --git a/src/internal/context/context.go b/src/internal/context/context.go new file mode 100644 index 0000000..68e2599 --- /dev/null +++ b/src/internal/context/context.go @@ -0,0 +1,74 @@ +package context + +import ( + "sync" + + mqtt_server "github.com/mochi-mqtt/server/v2" + + "ac/internal/mqtt/message" + "ac/pkg/factory" +) + +var acContext ACContext + +func init() { +} + +type ACContext struct { + ApPool sync.Map // map[mqtt_server.Client]*Ap + CapwapAddr string +} + +type Ap struct { + Client *mqtt_server.Client + LastEcho *message.Echo +} + +func InitAcContext(context *ACContext) { + config := factory.AcConfig + context.CapwapAddr = config.CapwapAddr +} + +func (context *ACContext) NewAp(client *mqtt_server.Client) *Ap { + ap := Ap{Client: client} + context.ApPool.Store(client, &ap) + return &ap +} + +// use mqtt_server.Client to find AP context, return *Ap and ok bit +func (context *ACContext) ApFindByClient(client *mqtt_server.Client) (*Ap, bool) { + if value, ok := context.ApPool.Load(client); ok { + return value.(*Ap), ok + } + return nil, false +} + +// use clientId to find AP context, return *Ap and ok bit +func (context *ACContext) ApFindByClientId(clientId string) (ap *Ap, ok bool) { + context.ApPool.Range(func(key, value interface{}) bool { + candidate := value.(*Ap) + if ok = (candidate.Client.ID == clientId); ok { + ap = candidate + return false + } + return true + }) + return +} + +func (context *ACContext) DeleteAp(client *mqtt_server.Client) { + context.ApPool.Delete(client) +} + +// Reset Ac Context +func (context *ACContext) Reset() { + context.ApPool.Range(func(key, value interface{}) bool { + context.ApPool.Delete(key) + return true + }) +} + +// Create new AC context +func GetSelf() *ACContext { + return &acContext +} diff --git a/src/internal/grpc_client/dhcpServer/dhcp_server.pb.go b/src/internal/grpc_client/dhcpServer/dhcp_server.pb.go new file mode 100644 index 0000000..eeb91fb --- /dev/null +++ b/src/internal/grpc_client/dhcpServer/dhcp_server.pb.go @@ -0,0 +1,189 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2-devel +// protoc v3.12.4 +// source: dhcp_server.proto + +package dhcpServer + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type MacAddr struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Mac string `protobuf:"bytes,1,opt,name=mac,proto3" json:"mac,omitempty"` +} + +func (x *MacAddr) Reset() { + *x = MacAddr{} + mi := &file_dhcp_server_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MacAddr) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MacAddr) ProtoMessage() {} + +func (x *MacAddr) ProtoReflect() protoreflect.Message { + mi := &file_dhcp_server_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MacAddr.ProtoReflect.Descriptor instead. +func (*MacAddr) Descriptor() ([]byte, []int) { + return file_dhcp_server_proto_rawDescGZIP(), []int{0} +} + +func (x *MacAddr) GetMac() string { + if x != nil { + return x.Mac + } + return "" +} + +// The response message containing the staInfo. +type StaDhcpInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` + Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"` +} + +func (x *StaDhcpInfo) Reset() { + *x = StaDhcpInfo{} + mi := &file_dhcp_server_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StaDhcpInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StaDhcpInfo) ProtoMessage() {} + +func (x *StaDhcpInfo) ProtoReflect() protoreflect.Message { + mi := &file_dhcp_server_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StaDhcpInfo.ProtoReflect.Descriptor instead. +func (*StaDhcpInfo) Descriptor() ([]byte, []int) { + return file_dhcp_server_proto_rawDescGZIP(), []int{1} +} + +func (x *StaDhcpInfo) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *StaDhcpInfo) GetHostname() string { + if x != nil { + return x.Hostname + } + return "" +} + +var File_dhcp_server_proto protoreflect.FileDescriptor + +var file_dhcp_server_proto_rawDesc = []byte{ + 0x0a, 0x11, 0x64, 0x68, 0x63, 0x70, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x22, 0x1b, 0x0a, 0x07, 0x4d, 0x61, 0x63, 0x41, 0x64, 0x64, 0x72, 0x12, 0x10, + 0x0a, 0x03, 0x6d, 0x61, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x61, 0x63, + 0x22, 0x39, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x44, 0x68, 0x63, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, + 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0x30, 0x0a, 0x0a, 0x53, + 0x74, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x22, 0x0a, 0x06, 0x47, 0x65, 0x74, + 0x53, 0x74, 0x61, 0x12, 0x08, 0x2e, 0x4d, 0x61, 0x63, 0x41, 0x64, 0x64, 0x72, 0x1a, 0x0c, 0x2e, + 0x53, 0x74, 0x61, 0x44, 0x68, 0x63, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x00, 0x42, 0x0e, 0x5a, + 0x0c, 0x2e, 0x2f, 0x64, 0x68, 0x63, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_dhcp_server_proto_rawDescOnce sync.Once + file_dhcp_server_proto_rawDescData = file_dhcp_server_proto_rawDesc +) + +func file_dhcp_server_proto_rawDescGZIP() []byte { + file_dhcp_server_proto_rawDescOnce.Do(func() { + file_dhcp_server_proto_rawDescData = protoimpl.X.CompressGZIP(file_dhcp_server_proto_rawDescData) + }) + return file_dhcp_server_proto_rawDescData +} + +var file_dhcp_server_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_dhcp_server_proto_goTypes = []any{ + (*MacAddr)(nil), // 0: MacAddr + (*StaDhcpInfo)(nil), // 1: StaDhcpInfo +} +var file_dhcp_server_proto_depIdxs = []int32{ + 0, // 0: StaService.GetSta:input_type -> MacAddr + 1, // 1: StaService.GetSta:output_type -> StaDhcpInfo + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_dhcp_server_proto_init() } +func file_dhcp_server_proto_init() { + if File_dhcp_server_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_dhcp_server_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_dhcp_server_proto_goTypes, + DependencyIndexes: file_dhcp_server_proto_depIdxs, + MessageInfos: file_dhcp_server_proto_msgTypes, + }.Build() + File_dhcp_server_proto = out.File + file_dhcp_server_proto_rawDesc = nil + file_dhcp_server_proto_goTypes = nil + file_dhcp_server_proto_depIdxs = nil +} diff --git a/src/internal/grpc_client/dhcpServer/dhcp_server.proto b/src/internal/grpc_client/dhcpServer/dhcp_server.proto new file mode 100644 index 0000000..d4ebb4b --- /dev/null +++ b/src/internal/grpc_client/dhcpServer/dhcp_server.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +option go_package = "./dhcpServer"; + +// The get service definition. +service StaService { + rpc GetSta(MacAddr) returns (StaDhcpInfo) {} +} + +message MacAddr { + string mac = 1; +} + +// The response message containing the staInfo. +message StaDhcpInfo { + string ip = 1; + string hostname = 2; +} diff --git a/src/internal/grpc_client/dhcpServer/dhcp_server_grpc.pb.go b/src/internal/grpc_client/dhcpServer/dhcp_server_grpc.pb.go new file mode 100644 index 0000000..0daec82 --- /dev/null +++ b/src/internal/grpc_client/dhcpServer/dhcp_server_grpc.pb.go @@ -0,0 +1,125 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.12.4 +// source: dhcp_server.proto + +package dhcpServer + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + StaService_GetSta_FullMethodName = "/StaService/GetSta" +) + +// StaServiceClient is the client API for StaService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// The get service definition. +type StaServiceClient interface { + GetSta(ctx context.Context, in *MacAddr, opts ...grpc.CallOption) (*StaDhcpInfo, error) +} + +type staServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewStaServiceClient(cc grpc.ClientConnInterface) StaServiceClient { + return &staServiceClient{cc} +} + +func (c *staServiceClient) GetSta(ctx context.Context, in *MacAddr, opts ...grpc.CallOption) (*StaDhcpInfo, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(StaDhcpInfo) + err := c.cc.Invoke(ctx, StaService_GetSta_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// StaServiceServer is the server API for StaService service. +// All implementations must embed UnimplementedStaServiceServer +// for forward compatibility. +// +// The get service definition. +type StaServiceServer interface { + GetSta(context.Context, *MacAddr) (*StaDhcpInfo, error) + mustEmbedUnimplementedStaServiceServer() +} + +// UnimplementedStaServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedStaServiceServer struct{} + +func (UnimplementedStaServiceServer) GetSta(context.Context, *MacAddr) (*StaDhcpInfo, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetSta not implemented") +} +func (UnimplementedStaServiceServer) mustEmbedUnimplementedStaServiceServer() {} +func (UnimplementedStaServiceServer) testEmbeddedByValue() {} + +// UnsafeStaServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StaServiceServer will +// result in compilation errors. +type UnsafeStaServiceServer interface { + mustEmbedUnimplementedStaServiceServer() +} + +func RegisterStaServiceServer(s grpc.ServiceRegistrar, srv StaServiceServer) { + // If the following call panics, it indicates UnimplementedStaServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&StaService_ServiceDesc, srv) +} + +func _StaService_GetSta_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MacAddr) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StaServiceServer).GetSta(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StaService_GetSta_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StaServiceServer).GetSta(ctx, req.(*MacAddr)) + } + return interceptor(ctx, in, info, handler) +} + +// StaService_ServiceDesc is the grpc.ServiceDesc for StaService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var StaService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "StaService", + HandlerType: (*StaServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetSta", + Handler: _StaService_GetSta_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "dhcp_server.proto", +} diff --git a/src/internal/grpc_client/grpc_client.go b/src/internal/grpc_client/grpc_client.go new file mode 100644 index 0000000..8cda2ef --- /dev/null +++ b/src/internal/grpc_client/grpc_client.go @@ -0,0 +1,38 @@ +package grpcClient + +import ( + "context" + "fmt" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + "ac/internal/grpc_client/dhcpServer" + "ac/internal/logger" +) + +var client dhcpServer.StaServiceClient + +func ConnectToServer(address string, port int) { + target := fmt.Sprintf("%s:%d", address, port) + + logger.GrpcLog.Infoln("connecting to target", target) + + var err error + conn, err := grpc.NewClient(target, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + logger.GrpcLog.Errorln("did not connect:", err) + return + } + + client = dhcpServer.NewStaServiceClient(conn) +} + +func GetStaInfo(mac string) (string, string) { + macAddr := dhcpServer.MacAddr{Mac: mac} + staInfo, _ := client.GetSta(context.Background(), &macAddr) + if staInfo != nil { + return staInfo.Ip, staInfo.Hostname + } + return "-", "-" +} diff --git a/src/internal/logger/logger.go b/src/internal/logger/logger.go new file mode 100644 index 0000000..ef09664 --- /dev/null +++ b/src/internal/logger/logger.go @@ -0,0 +1,64 @@ +package logger + +import ( + "fmt" + "path" + "runtime" + + "github.com/natefinch/lumberjack" + "github.com/sirupsen/logrus" + formatter "github.com/tim-ywliu/nested-logrus-formatter" +) + +var ( + Log *logrus.Logger + MainLog *logrus.Entry + InitLog *logrus.Entry + CfgLog *logrus.Entry + CtxLog *logrus.Entry + CapwapLog *logrus.Entry + MqttLog *logrus.Entry + GrpcLog *logrus.Entry +) + +const ( + FieldApAddr string = "ap_addr" +) + +func init() { + Log = logrus.New() + Log.SetReportCaller(true) + + Log.SetOutput(&lumberjack.Logger{ + Filename: "/var/log/ac.log", + MaxSize: 200, + MaxBackups: 9, + LocalTime: true, + }) + + Log.SetFormatter(&formatter.Formatter{ + FieldsOrder: []string{"CAT"}, + TimestampFormat: "2006-01-02 15:04:05.000", + TrimMessages: true, + NoColors: true, + NoFieldsColors: true, + NoFieldsSpace: true, + HideKeys: true, + CallerFirst: true, + CustomCallerFormatter: func(f *runtime.Frame) string { + file := path.Base(f.File) + if len(file) > 15 { + file = file[len(file)-15:] + } + return fmt.Sprintf(" %15s:%04d", file, f.Line) + }, + }) + + MainLog = Log.WithField("CAT", "Main") + InitLog = Log.WithField("CAT", "Init") + CfgLog = Log.WithField("CAT", "CFG") + CtxLog = Log.WithField("CAT", "CTX") + CapwapLog = Log.WithField("CAT", "Capwap") + MqttLog = Log.WithField("CAT", "MQTT") + GrpcLog = Log.WithField("CAT", "gRPC") +} diff --git a/src/internal/mqtt/message/message.pb.go b/src/internal/mqtt/message/message.pb.go new file mode 100644 index 0000000..b69cb36 --- /dev/null +++ b/src/internal/mqtt/message/message.pb.go @@ -0,0 +1,1646 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2-devel +// protoc v3.12.4 +// source: message.proto + +package message + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type APMode int32 + +const ( + APMode_FIT_AP APMode = 1 + APMode_FAT_AP APMode = 2 // soho + APMode_CPE_BASE APMode = 3 // CPE 基站 + APMode_CPE_STA APMode = 4 // CPE 接收端 +) + +// Enum value maps for APMode. +var ( + APMode_name = map[int32]string{ + 1: "FIT_AP", + 2: "FAT_AP", + 3: "CPE_BASE", + 4: "CPE_STA", + } + APMode_value = map[string]int32{ + "FIT_AP": 1, + "FAT_AP": 2, + "CPE_BASE": 3, + "CPE_STA": 4, + } +) + +func (x APMode) Enum() *APMode { + p := new(APMode) + *p = x + return p +} + +func (x APMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (APMode) Descriptor() protoreflect.EnumDescriptor { + return file_message_proto_enumTypes[0].Descriptor() +} + +func (APMode) Type() protoreflect.EnumType { + return &file_message_proto_enumTypes[0] +} + +func (x APMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *APMode) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = APMode(num) + return nil +} + +// Deprecated: Use APMode.Descriptor instead. +func (APMode) EnumDescriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{0} +} + +type RadioBand int32 + +const ( + RadioBand_RB_2G RadioBand = 1 + RadioBand_RB_5G RadioBand = 2 +) + +// Enum value maps for RadioBand. +var ( + RadioBand_name = map[int32]string{ + 1: "RB_2G", + 2: "RB_5G", + } + RadioBand_value = map[string]int32{ + "RB_2G": 1, + "RB_5G": 2, + } +) + +func (x RadioBand) Enum() *RadioBand { + p := new(RadioBand) + *p = x + return p +} + +func (x RadioBand) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RadioBand) Descriptor() protoreflect.EnumDescriptor { + return file_message_proto_enumTypes[1].Descriptor() +} + +func (RadioBand) Type() protoreflect.EnumType { + return &file_message_proto_enumTypes[1] +} + +func (x RadioBand) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *RadioBand) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = RadioBand(num) + return nil +} + +// Deprecated: Use RadioBand.Descriptor instead. +func (RadioBand) EnumDescriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{1} +} + +type RadioHTMode int32 + +const ( + RadioHTMode_RHT_20 RadioHTMode = 1 + RadioHTMode_RHT_40 RadioHTMode = 2 + RadioHTMode_RHT_40Minus RadioHTMode = 3 + RadioHTMode_RHT_40Plus RadioHTMode = 4 + RadioHTMode_RHT_80 RadioHTMode = 5 + RadioHTMode_RHT_160 RadioHTMode = 6 + RadioHTMode_RHT_160Plus RadioHTMode = 7 +) + +// Enum value maps for RadioHTMode. +var ( + RadioHTMode_name = map[int32]string{ + 1: "RHT_20", + 2: "RHT_40", + 3: "RHT_40Minus", + 4: "RHT_40Plus", + 5: "RHT_80", + 6: "RHT_160", + 7: "RHT_160Plus", + } + RadioHTMode_value = map[string]int32{ + "RHT_20": 1, + "RHT_40": 2, + "RHT_40Minus": 3, + "RHT_40Plus": 4, + "RHT_80": 5, + "RHT_160": 6, + "RHT_160Plus": 7, + } +) + +func (x RadioHTMode) Enum() *RadioHTMode { + p := new(RadioHTMode) + *p = x + return p +} + +func (x RadioHTMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RadioHTMode) Descriptor() protoreflect.EnumDescriptor { + return file_message_proto_enumTypes[2].Descriptor() +} + +func (RadioHTMode) Type() protoreflect.EnumType { + return &file_message_proto_enumTypes[2] +} + +func (x RadioHTMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *RadioHTMode) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = RadioHTMode(num) + return nil +} + +// Deprecated: Use RadioHTMode.Descriptor instead. +func (RadioHTMode) EnumDescriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{2} +} + +type CMDType int32 + +const ( + CMDType_REBOOT CMDType = 1 + CMDType_UPGRADE CMDType = 2 + CMDType_SETACADDR CMDType = 4 + // 解绑AP 和AC, AP 和AC 的绑定关系由配置下发时确定 + CMDType_UNBIND CMDType = 5 + // 下线用户支持 + CMDType_KICK_USER CMDType = 6 + // 配置设备名称 + CMDType_SETHOSTNAME CMDType = 7 + // 没有绑定的时候要求AP 断开和AC 的连接,重启查询AC 的流程 + CMDType_KICK_AP CMDType = 8 + // 启动扫描 + CMDType_START_SCAN CMDType = 9 + // 下发认证 + CMDType_AUTH CMDType = 10 + // 下线用户 + CMDType_LOGOUT CMDType = 11 + // 下线用户 + CMDType_REBOOTAP CMDType = 12 + CMDType_SHELL CMDType = 100 +) + +// Enum value maps for CMDType. +var ( + CMDType_name = map[int32]string{ + 1: "REBOOT", + 2: "UPGRADE", + 4: "SETACADDR", + 5: "UNBIND", + 6: "KICK_USER", + 7: "SETHOSTNAME", + 8: "KICK_AP", + 9: "START_SCAN", + 10: "AUTH", + 11: "LOGOUT", + 12: "REBOOTAP", + 100: "SHELL", + } + CMDType_value = map[string]int32{ + "REBOOT": 1, + "UPGRADE": 2, + "SETACADDR": 4, + "UNBIND": 5, + "KICK_USER": 6, + "SETHOSTNAME": 7, + "KICK_AP": 8, + "START_SCAN": 9, + "AUTH": 10, + "LOGOUT": 11, + "REBOOTAP": 12, + "SHELL": 100, + } +) + +func (x CMDType) Enum() *CMDType { + p := new(CMDType) + *p = x + return p +} + +func (x CMDType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CMDType) Descriptor() protoreflect.EnumDescriptor { + return file_message_proto_enumTypes[3].Descriptor() +} + +func (CMDType) Type() protoreflect.EnumType { + return &file_message_proto_enumTypes[3] +} + +func (x CMDType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *CMDType) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = CMDType(num) + return nil +} + +// Deprecated: Use CMDType.Descriptor instead. +func (CMDType) EnumDescriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{3} +} + +type WanConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ipproto *string `protobuf:"bytes,1,req,name=ipproto" json:"ipproto,omitempty"` + Ip *string `protobuf:"bytes,2,opt,name=ip" json:"ip,omitempty"` + Netmask *string `protobuf:"bytes,3,opt,name=netmask" json:"netmask,omitempty"` + Metric *int32 `protobuf:"varint,4,opt,name=metric" json:"metric,omitempty"` + Gateway *string `protobuf:"bytes,5,opt,name=gateway" json:"gateway,omitempty"` + Dns1 *string `protobuf:"bytes,6,opt,name=dns1" json:"dns1,omitempty"` + Dns2 *string `protobuf:"bytes,7,opt,name=dns2" json:"dns2,omitempty"` +} + +func (x *WanConfig) Reset() { + *x = WanConfig{} + mi := &file_message_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WanConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WanConfig) ProtoMessage() {} + +func (x *WanConfig) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WanConfig.ProtoReflect.Descriptor instead. +func (*WanConfig) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{0} +} + +func (x *WanConfig) GetIpproto() string { + if x != nil && x.Ipproto != nil { + return *x.Ipproto + } + return "" +} + +func (x *WanConfig) GetIp() string { + if x != nil && x.Ip != nil { + return *x.Ip + } + return "" +} + +func (x *WanConfig) GetNetmask() string { + if x != nil && x.Netmask != nil { + return *x.Netmask + } + return "" +} + +func (x *WanConfig) GetMetric() int32 { + if x != nil && x.Metric != nil { + return *x.Metric + } + return 0 +} + +func (x *WanConfig) GetGateway() string { + if x != nil && x.Gateway != nil { + return *x.Gateway + } + return "" +} + +func (x *WanConfig) GetDns1() string { + if x != nil && x.Dns1 != nil { + return *x.Dns1 + } + return "" +} + +func (x *WanConfig) GetDns2() string { + if x != nil && x.Dns2 != nil { + return *x.Dns2 + } + return "" +} + +type WlanConfig struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Band *RadioBand `protobuf:"varint,1,req,name=band,enum=RadioBand" json:"band,omitempty"` + Ssid *string `protobuf:"bytes,2,req,name=ssid" json:"ssid,omitempty"` + GbkEnable *int32 `protobuf:"varint,3,req,name=gbk_enable,json=gbkEnable,def=0" json:"gbk_enable,omitempty"` + Encryption *string `protobuf:"bytes,4,req,name=encryption" json:"encryption,omitempty"` + Key *string `protobuf:"bytes,5,opt,name=key" json:"key,omitempty"` + Disabled *int32 `protobuf:"varint,6,req,name=disabled,def=0" json:"disabled,omitempty"` + Vlan *int32 `protobuf:"varint,10,req,name=vlan,def=0" json:"vlan,omitempty"` + Maxsta *int32 `protobuf:"varint,11,req,name=maxsta,def=0" json:"maxsta,omitempty"` + Rejrssi *int32 `protobuf:"varint,12,req,name=rejrssi,def=-85" json:"rejrssi,omitempty"` + Wmm *int32 `protobuf:"varint,13,req,name=wmm,def=1" json:"wmm,omitempty"` + Isolate *int32 `protobuf:"varint,14,req,name=isolate,def=0" json:"isolate,omitempty"` + Hide *int32 `protobuf:"varint,15,req,name=hide,def=0" json:"hide,omitempty"` + Ieee80211R *int32 `protobuf:"varint,22,req,name=ieee80211r,def=0" json:"ieee80211r,omitempty"` + AuthType *int32 `protobuf:"varint,25,opt,name=auth_type,json=authType" json:"auth_type,omitempty"` // 认证类型,将认证方式和ssid 关联 +} + +// Default values for WlanConfig fields. +const ( + Default_WlanConfig_GbkEnable = int32(0) + Default_WlanConfig_Disabled = int32(0) + Default_WlanConfig_Vlan = int32(0) + Default_WlanConfig_Maxsta = int32(0) + Default_WlanConfig_Rejrssi = int32(-85) + Default_WlanConfig_Wmm = int32(1) + Default_WlanConfig_Isolate = int32(0) + Default_WlanConfig_Hide = int32(0) + Default_WlanConfig_Ieee80211R = int32(0) +) + +func (x *WlanConfig) Reset() { + *x = WlanConfig{} + mi := &file_message_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WlanConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WlanConfig) ProtoMessage() {} + +func (x *WlanConfig) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WlanConfig.ProtoReflect.Descriptor instead. +func (*WlanConfig) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{1} +} + +func (x *WlanConfig) GetBand() RadioBand { + if x != nil && x.Band != nil { + return *x.Band + } + return RadioBand_RB_2G +} + +func (x *WlanConfig) GetSsid() string { + if x != nil && x.Ssid != nil { + return *x.Ssid + } + return "" +} + +func (x *WlanConfig) GetGbkEnable() int32 { + if x != nil && x.GbkEnable != nil { + return *x.GbkEnable + } + return Default_WlanConfig_GbkEnable +} + +func (x *WlanConfig) GetEncryption() string { + if x != nil && x.Encryption != nil { + return *x.Encryption + } + return "" +} + +func (x *WlanConfig) GetKey() string { + if x != nil && x.Key != nil { + return *x.Key + } + return "" +} + +func (x *WlanConfig) GetDisabled() int32 { + if x != nil && x.Disabled != nil { + return *x.Disabled + } + return Default_WlanConfig_Disabled +} + +func (x *WlanConfig) GetVlan() int32 { + if x != nil && x.Vlan != nil { + return *x.Vlan + } + return Default_WlanConfig_Vlan +} + +func (x *WlanConfig) GetMaxsta() int32 { + if x != nil && x.Maxsta != nil { + return *x.Maxsta + } + return Default_WlanConfig_Maxsta +} + +func (x *WlanConfig) GetRejrssi() int32 { + if x != nil && x.Rejrssi != nil { + return *x.Rejrssi + } + return Default_WlanConfig_Rejrssi +} + +func (x *WlanConfig) GetWmm() int32 { + if x != nil && x.Wmm != nil { + return *x.Wmm + } + return Default_WlanConfig_Wmm +} + +func (x *WlanConfig) GetIsolate() int32 { + if x != nil && x.Isolate != nil { + return *x.Isolate + } + return Default_WlanConfig_Isolate +} + +func (x *WlanConfig) GetHide() int32 { + if x != nil && x.Hide != nil { + return *x.Hide + } + return Default_WlanConfig_Hide +} + +func (x *WlanConfig) GetIeee80211R() int32 { + if x != nil && x.Ieee80211R != nil { + return *x.Ieee80211R + } + return Default_WlanConfig_Ieee80211R +} + +func (x *WlanConfig) GetAuthType() int32 { + if x != nil && x.AuthType != nil { + return *x.AuthType + } + return 0 +} + +type PingWatchdog struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Enable *int32 `protobuf:"varint,1,req,name=enable" json:"enable,omitempty"` + Target *string `protobuf:"bytes,2,opt,name=target" json:"target,omitempty"` + PingInterval *int32 `protobuf:"varint,3,opt,name=ping_interval,json=pingInterval" json:"ping_interval,omitempty"` + PingFailures *int32 `protobuf:"varint,4,opt,name=ping_failures,json=pingFailures" json:"ping_failures,omitempty"` + PingTimeout *int32 `protobuf:"varint,5,opt,name=ping_timeout,json=pingTimeout" json:"ping_timeout,omitempty"` + PingWatchdogAction *int32 `protobuf:"varint,6,opt,name=ping_watchdog_action,json=pingWatchdogAction,def=3" json:"ping_watchdog_action,omitempty"` +} + +// Default values for PingWatchdog fields. +const ( + Default_PingWatchdog_PingWatchdogAction = int32(3) +) + +func (x *PingWatchdog) Reset() { + *x = PingWatchdog{} + mi := &file_message_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingWatchdog) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingWatchdog) ProtoMessage() {} + +func (x *PingWatchdog) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingWatchdog.ProtoReflect.Descriptor instead. +func (*PingWatchdog) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{2} +} + +func (x *PingWatchdog) GetEnable() int32 { + if x != nil && x.Enable != nil { + return *x.Enable + } + return 0 +} + +func (x *PingWatchdog) GetTarget() string { + if x != nil && x.Target != nil { + return *x.Target + } + return "" +} + +func (x *PingWatchdog) GetPingInterval() int32 { + if x != nil && x.PingInterval != nil { + return *x.PingInterval + } + return 0 +} + +func (x *PingWatchdog) GetPingFailures() int32 { + if x != nil && x.PingFailures != nil { + return *x.PingFailures + } + return 0 +} + +func (x *PingWatchdog) GetPingTimeout() int32 { + if x != nil && x.PingTimeout != nil { + return *x.PingTimeout + } + return 0 +} + +func (x *PingWatchdog) GetPingWatchdogAction() int32 { + if x != nil && x.PingWatchdogAction != nil { + return *x.PingWatchdogAction + } + return Default_PingWatchdog_PingWatchdogAction +} + +type CMD struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type *CMDType `protobuf:"varint,1,req,name=type,enum=CMDType" json:"type,omitempty"` + Args *string `protobuf:"bytes,2,opt,name=args" json:"args,omitempty"` +} + +func (x *CMD) Reset() { + *x = CMD{} + mi := &file_message_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CMD) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CMD) ProtoMessage() {} + +func (x *CMD) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CMD.ProtoReflect.Descriptor instead. +func (*CMD) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{3} +} + +func (x *CMD) GetType() CMDType { + if x != nil && x.Type != nil { + return *x.Type + } + return CMDType_REBOOT +} + +func (x *CMD) GetArgs() string { + if x != nil && x.Args != nil { + return *x.Args + } + return "" +} + +type Echo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Sn *string `protobuf:"bytes,1,req,name=sn" json:"sn,omitempty"` + ProductName *string `protobuf:"bytes,2,req,name=product_name,json=productName" json:"product_name,omitempty"` + // 标识设备的唯一MAC + Mac *string `protobuf:"bytes,3,opt,name=mac" json:"mac,omitempty"` + Board *string `protobuf:"bytes,4,opt,name=board" json:"board,omitempty"` + Hostname *string `protobuf:"bytes,5,opt,name=hostname" json:"hostname,omitempty"` + // 运行时间 + Uptime *string `protobuf:"bytes,6,opt,name=uptime" json:"uptime,omitempty"` + UptimeSec *uint64 `protobuf:"varint,61,opt,name=uptime_sec,json=uptimeSec" json:"uptime_sec,omitempty"` + Version *string `protobuf:"bytes,7,opt,name=version" json:"version,omitempty"` + Apmode *APMode `protobuf:"varint,8,req,name=apmode,enum=APMode,def=1" json:"apmode,omitempty"` + // 是否是第一次连接(要求下发配置) + Newconnect *int32 `protobuf:"varint,9,req,name=newconnect,def=0" json:"newconnect,omitempty"` + // 关键配置的MD5 值 + ApnetworkMd5 *string `protobuf:"bytes,10,opt,name=apnetwork_md5,json=apnetworkMd5" json:"apnetwork_md5,omitempty"` + Country *string `protobuf:"bytes,11,opt,name=country" json:"country,omitempty"` + // CPU 占用率 + Cpu *string `protobuf:"bytes,12,opt,name=cpu" json:"cpu,omitempty"` + // 是否云端管理的 + IsOnCloud *int32 `protobuf:"varint,13,opt,name=is_on_cloud,json=isOnCloud,def=0" json:"is_on_cloud,omitempty"` + Username *string `protobuf:"bytes,14,opt,name=username" json:"username,omitempty"` + // 通过设备的上下行总流量统计 + Uploadspeed *uint64 `protobuf:"varint,21,opt,name=uploadspeed" json:"uploadspeed,omitempty"` + Downloadspeed *uint64 `protobuf:"varint,22,opt,name=downloadspeed" json:"downloadspeed,omitempty"` + Uploadbytes *uint64 `protobuf:"varint,23,opt,name=uploadbytes" json:"uploadbytes,omitempty"` + Downloadbytes *uint64 `protobuf:"varint,24,opt,name=downloadbytes" json:"downloadbytes,omitempty"` + Acaddr *string `protobuf:"bytes,25,req,name=acaddr" json:"acaddr,omitempty"` + Mif *ManageInterface `protobuf:"bytes,50,req,name=mif" json:"mif,omitempty"` // 接口信息 + Radioinfo []*RadioInfo `protobuf:"bytes,51,rep,name=radioinfo" json:"radioinfo,omitempty"` // 射频信息 + Lanconfig *WanConfig `protobuf:"bytes,52,opt,name=lanconfig" json:"lanconfig,omitempty"` // lan 口配置 + Pingwatchdog *PingWatchdog `protobuf:"bytes,53,opt,name=pingwatchdog" json:"pingwatchdog,omitempty"` // Ping 看门狗 + Ssids []*WlanConfig `protobuf:"bytes,54,rep,name=ssids" json:"ssids,omitempty"` // ssid 配置 + IptvSupport *int32 `protobuf:"varint,70,opt,name=iptvSupport" json:"iptvSupport,omitempty"` + IptvEnable *int32 `protobuf:"varint,71,opt,name=iptvEnable" json:"iptvEnable,omitempty"` + // 增加一个CPE 专用的信息上报,信道列表 + CpeChannelsJson *string `protobuf:"bytes,100,opt,name=cpeChannelsJson" json:"cpeChannelsJson,omitempty"` +} + +// Default values for Echo fields. +const ( + Default_Echo_Apmode = APMode_FIT_AP + Default_Echo_Newconnect = int32(0) + Default_Echo_IsOnCloud = int32(0) +) + +func (x *Echo) Reset() { + *x = Echo{} + mi := &file_message_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Echo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Echo) ProtoMessage() {} + +func (x *Echo) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Echo.ProtoReflect.Descriptor instead. +func (*Echo) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{4} +} + +func (x *Echo) GetSn() string { + if x != nil && x.Sn != nil { + return *x.Sn + } + return "" +} + +func (x *Echo) GetProductName() string { + if x != nil && x.ProductName != nil { + return *x.ProductName + } + return "" +} + +func (x *Echo) GetMac() string { + if x != nil && x.Mac != nil { + return *x.Mac + } + return "" +} + +func (x *Echo) GetBoard() string { + if x != nil && x.Board != nil { + return *x.Board + } + return "" +} + +func (x *Echo) GetHostname() string { + if x != nil && x.Hostname != nil { + return *x.Hostname + } + return "" +} + +func (x *Echo) GetUptime() string { + if x != nil && x.Uptime != nil { + return *x.Uptime + } + return "" +} + +func (x *Echo) GetUptimeSec() uint64 { + if x != nil && x.UptimeSec != nil { + return *x.UptimeSec + } + return 0 +} + +func (x *Echo) GetVersion() string { + if x != nil && x.Version != nil { + return *x.Version + } + return "" +} + +func (x *Echo) GetApmode() APMode { + if x != nil && x.Apmode != nil { + return *x.Apmode + } + return Default_Echo_Apmode +} + +func (x *Echo) GetNewconnect() int32 { + if x != nil && x.Newconnect != nil { + return *x.Newconnect + } + return Default_Echo_Newconnect +} + +func (x *Echo) GetApnetworkMd5() string { + if x != nil && x.ApnetworkMd5 != nil { + return *x.ApnetworkMd5 + } + return "" +} + +func (x *Echo) GetCountry() string { + if x != nil && x.Country != nil { + return *x.Country + } + return "" +} + +func (x *Echo) GetCpu() string { + if x != nil && x.Cpu != nil { + return *x.Cpu + } + return "" +} + +func (x *Echo) GetIsOnCloud() int32 { + if x != nil && x.IsOnCloud != nil { + return *x.IsOnCloud + } + return Default_Echo_IsOnCloud +} + +func (x *Echo) GetUsername() string { + if x != nil && x.Username != nil { + return *x.Username + } + return "" +} + +func (x *Echo) GetUploadspeed() uint64 { + if x != nil && x.Uploadspeed != nil { + return *x.Uploadspeed + } + return 0 +} + +func (x *Echo) GetDownloadspeed() uint64 { + if x != nil && x.Downloadspeed != nil { + return *x.Downloadspeed + } + return 0 +} + +func (x *Echo) GetUploadbytes() uint64 { + if x != nil && x.Uploadbytes != nil { + return *x.Uploadbytes + } + return 0 +} + +func (x *Echo) GetDownloadbytes() uint64 { + if x != nil && x.Downloadbytes != nil { + return *x.Downloadbytes + } + return 0 +} + +func (x *Echo) GetAcaddr() string { + if x != nil && x.Acaddr != nil { + return *x.Acaddr + } + return "" +} + +func (x *Echo) GetMif() *ManageInterface { + if x != nil { + return x.Mif + } + return nil +} + +func (x *Echo) GetRadioinfo() []*RadioInfo { + if x != nil { + return x.Radioinfo + } + return nil +} + +func (x *Echo) GetLanconfig() *WanConfig { + if x != nil { + return x.Lanconfig + } + return nil +} + +func (x *Echo) GetPingwatchdog() *PingWatchdog { + if x != nil { + return x.Pingwatchdog + } + return nil +} + +func (x *Echo) GetSsids() []*WlanConfig { + if x != nil { + return x.Ssids + } + return nil +} + +func (x *Echo) GetIptvSupport() int32 { + if x != nil && x.IptvSupport != nil { + return *x.IptvSupport + } + return 0 +} + +func (x *Echo) GetIptvEnable() int32 { + if x != nil && x.IptvEnable != nil { + return *x.IptvEnable + } + return 0 +} + +func (x *Echo) GetCpeChannelsJson() string { + if x != nil && x.CpeChannelsJson != nil { + return *x.CpeChannelsJson + } + return "" +} + +type StaInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Mac *string `protobuf:"bytes,2,req,name=mac" json:"mac,omitempty"` + Ip *string `protobuf:"bytes,3,opt,name=ip" json:"ip,omitempty"` + Signal *int32 `protobuf:"varint,4,req,name=signal" json:"signal,omitempty"` + Noise *int32 `protobuf:"varint,5,req,name=noise" json:"noise,omitempty"` + Snr *int32 `protobuf:"varint,6,req,name=snr" json:"snr,omitempty"` + Txrate *string `protobuf:"bytes,7,req,name=txrate" json:"txrate,omitempty"` + Rxrate *string `protobuf:"bytes,8,req,name=rxrate" json:"rxrate,omitempty"` +} + +func (x *StaInfo) Reset() { + *x = StaInfo{} + mi := &file_message_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *StaInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StaInfo) ProtoMessage() {} + +func (x *StaInfo) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StaInfo.ProtoReflect.Descriptor instead. +func (*StaInfo) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{5} +} + +func (x *StaInfo) GetMac() string { + if x != nil && x.Mac != nil { + return *x.Mac + } + return "" +} + +func (x *StaInfo) GetIp() string { + if x != nil && x.Ip != nil { + return *x.Ip + } + return "" +} + +func (x *StaInfo) GetSignal() int32 { + if x != nil && x.Signal != nil { + return *x.Signal + } + return 0 +} + +func (x *StaInfo) GetNoise() int32 { + if x != nil && x.Noise != nil { + return *x.Noise + } + return 0 +} + +func (x *StaInfo) GetSnr() int32 { + if x != nil && x.Snr != nil { + return *x.Snr + } + return 0 +} + +func (x *StaInfo) GetTxrate() string { + if x != nil && x.Txrate != nil { + return *x.Txrate + } + return "" +} + +func (x *StaInfo) GetRxrate() string { + if x != nil && x.Rxrate != nil { + return *x.Rxrate + } + return "" +} + +type WlanInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ssid *string `protobuf:"bytes,1,opt,name=ssid" json:"ssid,omitempty"` + Stas []*StaInfo `protobuf:"bytes,2,rep,name=stas" json:"stas,omitempty"` +} + +func (x *WlanInfo) Reset() { + *x = WlanInfo{} + mi := &file_message_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WlanInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WlanInfo) ProtoMessage() {} + +func (x *WlanInfo) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use WlanInfo.ProtoReflect.Descriptor instead. +func (*WlanInfo) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{6} +} + +func (x *WlanInfo) GetSsid() string { + if x != nil && x.Ssid != nil { + return *x.Ssid + } + return "" +} + +func (x *WlanInfo) GetStas() []*StaInfo { + if x != nil { + return x.Stas + } + return nil +} + +type RadioInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Band *RadioBand `protobuf:"varint,1,req,name=band,enum=RadioBand" json:"band,omitempty"` + Wlaninfo []*WlanInfo `protobuf:"bytes,2,rep,name=wlaninfo" json:"wlaninfo,omitempty"` + // 基础三属性 + Htmode *RadioHTMode `protobuf:"varint,3,req,name=htmode,enum=RadioHTMode,def=1" json:"htmode,omitempty"` + Txpower *uint32 `protobuf:"varint,4,req,name=txpower,def=0" json:"txpower,omitempty"` + Channel *uint32 `protobuf:"varint,5,req,name=channel,def=0" json:"channel,omitempty"` + // 其他属性 + Signal *int32 `protobuf:"varint,20,opt,name=signal" json:"signal,omitempty"` + Noise *int32 `protobuf:"varint,21,opt,name=noise" json:"noise,omitempty"` + Bitrate *string `protobuf:"bytes,22,opt,name=bitrate" json:"bitrate,omitempty"` + // 增加字段 + Maxsta *int32 `protobuf:"varint,23,opt,name=maxsta,def=0" json:"maxsta,omitempty"` + Rejrssi *int32 `protobuf:"varint,24,opt,name=rejrssi,def=-85" json:"rejrssi,omitempty"` + Country *string `protobuf:"bytes,25,opt,name=country" json:"country,omitempty"` + EnableFils *int32 `protobuf:"varint,26,opt,name=enable_fils,json=enableFils,def=1" json:"enable_fils,omitempty"` + Mac *string `protobuf:"bytes,27,opt,name=mac" json:"mac,omitempty"` +} + +// Default values for RadioInfo fields. +const ( + Default_RadioInfo_Htmode = RadioHTMode_RHT_20 + Default_RadioInfo_Txpower = uint32(0) + Default_RadioInfo_Channel = uint32(0) + Default_RadioInfo_Maxsta = int32(0) + Default_RadioInfo_Rejrssi = int32(-85) + Default_RadioInfo_EnableFils = int32(1) +) + +func (x *RadioInfo) Reset() { + *x = RadioInfo{} + mi := &file_message_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RadioInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RadioInfo) ProtoMessage() {} + +func (x *RadioInfo) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RadioInfo.ProtoReflect.Descriptor instead. +func (*RadioInfo) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{7} +} + +func (x *RadioInfo) GetBand() RadioBand { + if x != nil && x.Band != nil { + return *x.Band + } + return RadioBand_RB_2G +} + +func (x *RadioInfo) GetWlaninfo() []*WlanInfo { + if x != nil { + return x.Wlaninfo + } + return nil +} + +func (x *RadioInfo) GetHtmode() RadioHTMode { + if x != nil && x.Htmode != nil { + return *x.Htmode + } + return Default_RadioInfo_Htmode +} + +func (x *RadioInfo) GetTxpower() uint32 { + if x != nil && x.Txpower != nil { + return *x.Txpower + } + return Default_RadioInfo_Txpower +} + +func (x *RadioInfo) GetChannel() uint32 { + if x != nil && x.Channel != nil { + return *x.Channel + } + return Default_RadioInfo_Channel +} + +func (x *RadioInfo) GetSignal() int32 { + if x != nil && x.Signal != nil { + return *x.Signal + } + return 0 +} + +func (x *RadioInfo) GetNoise() int32 { + if x != nil && x.Noise != nil { + return *x.Noise + } + return 0 +} + +func (x *RadioInfo) GetBitrate() string { + if x != nil && x.Bitrate != nil { + return *x.Bitrate + } + return "" +} + +func (x *RadioInfo) GetMaxsta() int32 { + if x != nil && x.Maxsta != nil { + return *x.Maxsta + } + return Default_RadioInfo_Maxsta +} + +func (x *RadioInfo) GetRejrssi() int32 { + if x != nil && x.Rejrssi != nil { + return *x.Rejrssi + } + return Default_RadioInfo_Rejrssi +} + +func (x *RadioInfo) GetCountry() string { + if x != nil && x.Country != nil { + return *x.Country + } + return "" +} + +func (x *RadioInfo) GetEnableFils() int32 { + if x != nil && x.EnableFils != nil { + return *x.EnableFils + } + return Default_RadioInfo_EnableFils +} + +func (x *RadioInfo) GetMac() string { + if x != nil && x.Mac != nil { + return *x.Mac + } + return "" +} + +type ManageInterface struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ifname *string `protobuf:"bytes,1,req,name=ifname" json:"ifname,omitempty"` + Ip *string `protobuf:"bytes,2,opt,name=ip" json:"ip,omitempty"` + Mac *string `protobuf:"bytes,3,opt,name=mac" json:"mac,omitempty"` + Netmask *string `protobuf:"bytes,4,opt,name=netmask" json:"netmask,omitempty"` + Gateway *string `protobuf:"bytes,5,opt,name=gateway" json:"gateway,omitempty"` + Dns1 *string `protobuf:"bytes,6,opt,name=dns1" json:"dns1,omitempty"` + Dns2 *string `protobuf:"bytes,7,opt,name=dns2" json:"dns2,omitempty"` + Ipproto *string `protobuf:"bytes,8,opt,name=ipproto" json:"ipproto,omitempty"` // dhcp static pppoe +} + +func (x *ManageInterface) Reset() { + *x = ManageInterface{} + mi := &file_message_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ManageInterface) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ManageInterface) ProtoMessage() {} + +func (x *ManageInterface) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ManageInterface.ProtoReflect.Descriptor instead. +func (*ManageInterface) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{8} +} + +func (x *ManageInterface) GetIfname() string { + if x != nil && x.Ifname != nil { + return *x.Ifname + } + return "" +} + +func (x *ManageInterface) GetIp() string { + if x != nil && x.Ip != nil { + return *x.Ip + } + return "" +} + +func (x *ManageInterface) GetMac() string { + if x != nil && x.Mac != nil { + return *x.Mac + } + return "" +} + +func (x *ManageInterface) GetNetmask() string { + if x != nil && x.Netmask != nil { + return *x.Netmask + } + return "" +} + +func (x *ManageInterface) GetGateway() string { + if x != nil && x.Gateway != nil { + return *x.Gateway + } + return "" +} + +func (x *ManageInterface) GetDns1() string { + if x != nil && x.Dns1 != nil { + return *x.Dns1 + } + return "" +} + +func (x *ManageInterface) GetDns2() string { + if x != nil && x.Dns2 != nil { + return *x.Dns2 + } + return "" +} + +func (x *ManageInterface) GetIpproto() string { + if x != nil && x.Ipproto != nil { + return *x.Ipproto + } + return "" +} + +var File_message_proto protoreflect.FileDescriptor + +var file_message_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0xa9, 0x01, 0x0a, 0x09, 0x57, 0x61, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x18, 0x0a, + 0x07, 0x69, 0x70, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x07, + 0x69, 0x70, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x6d, 0x61, + 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6e, 0x65, 0x74, 0x6d, 0x61, 0x73, + 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6e, 0x73, 0x31, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x64, 0x6e, 0x73, 0x31, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6e, 0x73, 0x32, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x6e, 0x73, 0x32, 0x22, 0x8d, 0x03, 0x0a, 0x0a, + 0x57, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x04, 0x62, 0x61, + 0x6e, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x52, 0x61, 0x64, 0x69, 0x6f, + 0x42, 0x61, 0x6e, 0x64, 0x52, 0x04, 0x62, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x73, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x73, 0x73, 0x69, 0x64, 0x12, 0x20, + 0x0a, 0x0a, 0x67, 0x62, 0x6b, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x02, + 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x09, 0x67, 0x62, 0x6b, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, + 0x20, 0x02, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x06, + 0x20, 0x02, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x12, 0x15, 0x0a, 0x04, 0x76, 0x6c, 0x61, 0x6e, 0x18, 0x0a, 0x20, 0x02, 0x28, 0x05, 0x3a, + 0x01, 0x30, 0x52, 0x04, 0x76, 0x6c, 0x61, 0x6e, 0x12, 0x19, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x73, + 0x74, 0x61, 0x18, 0x0b, 0x20, 0x02, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x06, 0x6d, 0x61, 0x78, + 0x73, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x07, 0x72, 0x65, 0x6a, 0x72, 0x73, 0x73, 0x69, 0x18, 0x0c, + 0x20, 0x02, 0x28, 0x05, 0x3a, 0x03, 0x2d, 0x38, 0x35, 0x52, 0x07, 0x72, 0x65, 0x6a, 0x72, 0x73, + 0x73, 0x69, 0x12, 0x13, 0x0a, 0x03, 0x77, 0x6d, 0x6d, 0x18, 0x0d, 0x20, 0x02, 0x28, 0x05, 0x3a, + 0x01, 0x31, 0x52, 0x03, 0x77, 0x6d, 0x6d, 0x12, 0x1b, 0x0a, 0x07, 0x69, 0x73, 0x6f, 0x6c, 0x61, + 0x74, 0x65, 0x18, 0x0e, 0x20, 0x02, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x07, 0x69, 0x73, 0x6f, + 0x6c, 0x61, 0x74, 0x65, 0x12, 0x15, 0x0a, 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x0f, 0x20, 0x02, + 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x04, 0x68, 0x69, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x69, + 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x31, 0x31, 0x72, 0x18, 0x16, 0x20, 0x02, 0x28, 0x05, 0x3a, + 0x01, 0x30, 0x52, 0x0a, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x31, 0x31, 0x72, 0x12, 0x1b, + 0x0a, 0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x08, 0x61, 0x75, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x22, 0xe0, 0x01, 0x0a, 0x0c, + 0x50, 0x69, 0x6e, 0x67, 0x57, 0x61, 0x74, 0x63, 0x68, 0x64, 0x6f, 0x67, 0x12, 0x16, 0x0a, 0x06, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x05, 0x52, 0x06, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x23, 0x0a, 0x0d, + 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, + 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, + 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x46, 0x61, + 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x70, 0x69, + 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x33, 0x0a, 0x14, 0x70, 0x69, 0x6e, + 0x67, 0x5f, 0x77, 0x61, 0x74, 0x63, 0x68, 0x64, 0x6f, 0x67, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x33, 0x52, 0x12, 0x70, 0x69, 0x6e, 0x67, + 0x57, 0x61, 0x74, 0x63, 0x68, 0x64, 0x6f, 0x67, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x37, + 0x0a, 0x03, 0x43, 0x4d, 0x44, 0x12, 0x1c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, + 0x02, 0x28, 0x0e, 0x32, 0x08, 0x2e, 0x43, 0x4d, 0x44, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x22, 0x8c, 0x07, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, + 0x12, 0x0e, 0x0a, 0x02, 0x73, 0x6e, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x73, 0x6e, + 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6d, 0x61, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x68, + 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, + 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x12, + 0x1d, 0x0a, 0x0a, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x63, 0x18, 0x3d, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x63, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x06, 0x61, 0x70, 0x6d, 0x6f, + 0x64, 0x65, 0x18, 0x08, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x07, 0x2e, 0x41, 0x50, 0x4d, 0x6f, 0x64, + 0x65, 0x3a, 0x06, 0x46, 0x49, 0x54, 0x5f, 0x41, 0x50, 0x52, 0x06, 0x61, 0x70, 0x6d, 0x6f, 0x64, + 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6e, 0x65, 0x77, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x18, + 0x09, 0x20, 0x02, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x0a, 0x6e, 0x65, 0x77, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x70, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, + 0x6b, 0x5f, 0x6d, 0x64, 0x35, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x70, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4d, 0x64, 0x35, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, 0x21, 0x0a, 0x0b, 0x69, 0x73, 0x5f, 0x6f, 0x6e, 0x5f, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x09, 0x69, + 0x73, 0x4f, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x70, + 0x65, 0x65, 0x64, 0x18, 0x15, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x73, 0x70, 0x65, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x16, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x64, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x70, 0x65, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, + 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x62, 0x79, 0x74, 0x65, 0x73, 0x12, 0x24, + 0x0a, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, + 0x18, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x62, + 0x79, 0x74, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x18, 0x19, + 0x20, 0x02, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x12, 0x22, 0x0a, 0x03, + 0x6d, 0x69, 0x66, 0x18, 0x32, 0x20, 0x02, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x4d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x52, 0x03, 0x6d, 0x69, 0x66, + 0x12, 0x28, 0x0a, 0x09, 0x72, 0x61, 0x64, 0x69, 0x6f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x33, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x61, 0x64, 0x69, 0x6f, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x09, 0x72, 0x61, 0x64, 0x69, 0x6f, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x28, 0x0a, 0x09, 0x6c, 0x61, + 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, + 0x57, 0x61, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x09, 0x6c, 0x61, 0x6e, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x0a, 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x77, 0x61, 0x74, 0x63, + 0x68, 0x64, 0x6f, 0x67, 0x18, 0x35, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x50, 0x69, 0x6e, + 0x67, 0x57, 0x61, 0x74, 0x63, 0x68, 0x64, 0x6f, 0x67, 0x52, 0x0c, 0x70, 0x69, 0x6e, 0x67, 0x77, + 0x61, 0x74, 0x63, 0x68, 0x64, 0x6f, 0x67, 0x12, 0x21, 0x0a, 0x05, 0x73, 0x73, 0x69, 0x64, 0x73, + 0x18, 0x36, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x57, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x52, 0x05, 0x73, 0x73, 0x69, 0x64, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x70, + 0x74, 0x76, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x46, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0b, 0x69, 0x70, 0x74, 0x76, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1e, 0x0a, 0x0a, + 0x69, 0x70, 0x74, 0x76, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x47, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0a, 0x69, 0x70, 0x74, 0x76, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x28, 0x0a, 0x0f, + 0x63, 0x70, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x4a, 0x73, 0x6f, 0x6e, 0x18, + 0x64, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x70, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x73, 0x4a, 0x73, 0x6f, 0x6e, 0x22, 0x9b, 0x01, 0x0a, 0x07, 0x53, 0x74, 0x61, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x63, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, + 0x03, 0x6d, 0x61, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x04, + 0x20, 0x02, 0x28, 0x05, 0x52, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, + 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x18, 0x05, 0x20, 0x02, 0x28, 0x05, 0x52, 0x05, 0x6e, 0x6f, 0x69, + 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x6e, 0x72, 0x18, 0x06, 0x20, 0x02, 0x28, 0x05, 0x52, + 0x03, 0x73, 0x6e, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x78, 0x72, 0x61, 0x74, 0x65, 0x18, 0x07, + 0x20, 0x02, 0x28, 0x09, 0x52, 0x06, 0x74, 0x78, 0x72, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x72, 0x78, 0x72, 0x61, 0x74, 0x65, 0x18, 0x08, 0x20, 0x02, 0x28, 0x09, 0x52, 0x06, 0x72, 0x78, + 0x72, 0x61, 0x74, 0x65, 0x22, 0x3c, 0x0a, 0x08, 0x57, 0x6c, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x12, 0x0a, 0x04, 0x73, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x73, 0x73, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x04, 0x73, 0x74, 0x61, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x53, 0x74, 0x61, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x04, 0x73, 0x74, + 0x61, 0x73, 0x22, 0x8c, 0x03, 0x0a, 0x09, 0x52, 0x61, 0x64, 0x69, 0x6f, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x1e, 0x0a, 0x04, 0x62, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x0a, + 0x2e, 0x52, 0x61, 0x64, 0x69, 0x6f, 0x42, 0x61, 0x6e, 0x64, 0x52, 0x04, 0x62, 0x61, 0x6e, 0x64, + 0x12, 0x25, 0x0a, 0x08, 0x77, 0x6c, 0x61, 0x6e, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x57, 0x6c, 0x61, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x77, + 0x6c, 0x61, 0x6e, 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x2c, 0x0a, 0x06, 0x68, 0x74, 0x6d, 0x6f, 0x64, + 0x65, 0x18, 0x03, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x52, 0x61, 0x64, 0x69, 0x6f, 0x48, + 0x54, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x06, 0x52, 0x48, 0x54, 0x5f, 0x32, 0x30, 0x52, 0x06, 0x68, + 0x74, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x07, 0x74, 0x78, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x18, 0x04, 0x20, 0x02, 0x28, 0x0d, 0x3a, 0x01, 0x30, 0x52, 0x07, 0x74, 0x78, 0x70, 0x6f, 0x77, + 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x05, 0x20, + 0x02, 0x28, 0x0d, 0x3a, 0x01, 0x30, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x69, 0x73, 0x65, + 0x18, 0x15, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6e, 0x6f, 0x69, 0x73, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x06, 0x6d, 0x61, 0x78, 0x73, 0x74, + 0x61, 0x18, 0x17, 0x20, 0x01, 0x28, 0x05, 0x3a, 0x01, 0x30, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x73, + 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x07, 0x72, 0x65, 0x6a, 0x72, 0x73, 0x73, 0x69, 0x18, 0x18, 0x20, + 0x01, 0x28, 0x05, 0x3a, 0x03, 0x2d, 0x38, 0x35, 0x52, 0x07, 0x72, 0x65, 0x6a, 0x72, 0x73, 0x73, + 0x69, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x19, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x22, 0x0a, 0x0b, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x73, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x05, + 0x3a, 0x01, 0x31, 0x52, 0x0a, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x73, 0x12, + 0x10, 0x0a, 0x03, 0x6d, 0x61, 0x63, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x61, + 0x63, 0x22, 0xc1, 0x01, 0x0a, 0x0f, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x06, 0x69, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x10, 0x0a, + 0x03, 0x6d, 0x61, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x61, 0x63, 0x12, + 0x18, 0x0a, 0x07, 0x6e, 0x65, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6e, 0x65, 0x74, 0x6d, 0x61, 0x73, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6e, 0x73, 0x31, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x64, 0x6e, 0x73, 0x31, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x6e, 0x73, 0x32, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x6e, 0x73, 0x32, 0x12, 0x18, 0x0a, 0x07, 0x69, + 0x70, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x70, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, 0x3b, 0x0a, 0x06, 0x41, 0x50, 0x4d, 0x6f, 0x64, 0x65, 0x12, + 0x0a, 0x0a, 0x06, 0x46, 0x49, 0x54, 0x5f, 0x41, 0x50, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x46, + 0x41, 0x54, 0x5f, 0x41, 0x50, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x50, 0x45, 0x5f, 0x42, + 0x41, 0x53, 0x45, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, + 0x10, 0x04, 0x2a, 0x21, 0x0a, 0x09, 0x52, 0x61, 0x64, 0x69, 0x6f, 0x42, 0x61, 0x6e, 0x64, 0x12, + 0x09, 0x0a, 0x05, 0x52, 0x42, 0x5f, 0x32, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x42, + 0x5f, 0x35, 0x47, 0x10, 0x02, 0x2a, 0x70, 0x0a, 0x0b, 0x52, 0x61, 0x64, 0x69, 0x6f, 0x48, 0x54, + 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x48, 0x54, 0x5f, 0x32, 0x30, 0x10, 0x01, + 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x48, 0x54, 0x5f, 0x34, 0x30, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, + 0x52, 0x48, 0x54, 0x5f, 0x34, 0x30, 0x4d, 0x69, 0x6e, 0x75, 0x73, 0x10, 0x03, 0x12, 0x0e, 0x0a, + 0x0a, 0x52, 0x48, 0x54, 0x5f, 0x34, 0x30, 0x50, 0x6c, 0x75, 0x73, 0x10, 0x04, 0x12, 0x0a, 0x0a, + 0x06, 0x52, 0x48, 0x54, 0x5f, 0x38, 0x30, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x48, 0x54, + 0x5f, 0x31, 0x36, 0x30, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x48, 0x54, 0x5f, 0x31, 0x36, + 0x30, 0x50, 0x6c, 0x75, 0x73, 0x10, 0x07, 0x2a, 0xa9, 0x01, 0x0a, 0x07, 0x43, 0x4d, 0x44, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x42, 0x4f, 0x4f, 0x54, 0x10, 0x01, 0x12, + 0x0b, 0x0a, 0x07, 0x55, 0x50, 0x47, 0x52, 0x41, 0x44, 0x45, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, + 0x53, 0x45, 0x54, 0x41, 0x43, 0x41, 0x44, 0x44, 0x52, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, 0x55, + 0x4e, 0x42, 0x49, 0x4e, 0x44, 0x10, 0x05, 0x12, 0x0d, 0x0a, 0x09, 0x4b, 0x49, 0x43, 0x4b, 0x5f, + 0x55, 0x53, 0x45, 0x52, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x45, 0x54, 0x48, 0x4f, 0x53, + 0x54, 0x4e, 0x41, 0x4d, 0x45, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x4b, 0x49, 0x43, 0x4b, 0x5f, + 0x41, 0x50, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x54, 0x41, 0x52, 0x54, 0x5f, 0x53, 0x43, + 0x41, 0x4e, 0x10, 0x09, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x55, 0x54, 0x48, 0x10, 0x0a, 0x12, 0x0a, + 0x0a, 0x06, 0x4c, 0x4f, 0x47, 0x4f, 0x55, 0x54, 0x10, 0x0b, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, + 0x42, 0x4f, 0x4f, 0x54, 0x41, 0x50, 0x10, 0x0c, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x48, 0x45, 0x4c, + 0x4c, 0x10, 0x64, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, +} + +var ( + file_message_proto_rawDescOnce sync.Once + file_message_proto_rawDescData = file_message_proto_rawDesc +) + +func file_message_proto_rawDescGZIP() []byte { + file_message_proto_rawDescOnce.Do(func() { + file_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_proto_rawDescData) + }) + return file_message_proto_rawDescData +} + +var file_message_proto_enumTypes = make([]protoimpl.EnumInfo, 4) +var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_message_proto_goTypes = []any{ + (APMode)(0), // 0: APMode + (RadioBand)(0), // 1: RadioBand + (RadioHTMode)(0), // 2: RadioHTMode + (CMDType)(0), // 3: CMDType + (*WanConfig)(nil), // 4: WanConfig + (*WlanConfig)(nil), // 5: WlanConfig + (*PingWatchdog)(nil), // 6: PingWatchdog + (*CMD)(nil), // 7: CMD + (*Echo)(nil), // 8: Echo + (*StaInfo)(nil), // 9: StaInfo + (*WlanInfo)(nil), // 10: WlanInfo + (*RadioInfo)(nil), // 11: RadioInfo + (*ManageInterface)(nil), // 12: ManageInterface +} +var file_message_proto_depIdxs = []int32{ + 1, // 0: WlanConfig.band:type_name -> RadioBand + 3, // 1: CMD.type:type_name -> CMDType + 0, // 2: Echo.apmode:type_name -> APMode + 12, // 3: Echo.mif:type_name -> ManageInterface + 11, // 4: Echo.radioinfo:type_name -> RadioInfo + 4, // 5: Echo.lanconfig:type_name -> WanConfig + 6, // 6: Echo.pingwatchdog:type_name -> PingWatchdog + 5, // 7: Echo.ssids:type_name -> WlanConfig + 9, // 8: WlanInfo.stas:type_name -> StaInfo + 1, // 9: RadioInfo.band:type_name -> RadioBand + 10, // 10: RadioInfo.wlaninfo:type_name -> WlanInfo + 2, // 11: RadioInfo.htmode:type_name -> RadioHTMode + 12, // [12:12] is the sub-list for method output_type + 12, // [12:12] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_message_proto_init() } +func file_message_proto_init() { + if File_message_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_message_proto_rawDesc, + NumEnums: 4, + NumMessages: 9, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_message_proto_goTypes, + DependencyIndexes: file_message_proto_depIdxs, + EnumInfos: file_message_proto_enumTypes, + MessageInfos: file_message_proto_msgTypes, + }.Build() + File_message_proto = out.File + file_message_proto_rawDesc = nil + file_message_proto_goTypes = nil + file_message_proto_depIdxs = nil +} diff --git a/src/internal/mqtt/message/message.proto b/src/internal/mqtt/message/message.proto new file mode 100644 index 0000000..e6f7fa1 --- /dev/null +++ b/src/internal/mqtt/message/message.proto @@ -0,0 +1,190 @@ +syntax = "proto2"; + +option go_package = "./message"; + +enum APMode { + FIT_AP = 1; + FAT_AP = 2; /* soho */ + CPE_BASE = 3; /* CPE 基站*/ + CPE_STA = 4; /* CPE 接收端*/ +} + +enum RadioBand { + RB_2G = 1; + RB_5G = 2; +} + +enum RadioHTMode { + RHT_20 = 1; + RHT_40 = 2; + RHT_40Minus = 3; + RHT_40Plus = 4; + RHT_80 = 5; + RHT_160 = 6; + RHT_160Plus = 7; +} + +enum CMDType { + REBOOT = 1; + UPGRADE = 2; + SETACADDR = 4; + /* 解绑AP 和AC, AP 和AC 的绑定关系由配置下发时确定*/ + UNBIND = 5; + /* 下线用户支持*/ + KICK_USER = 6; + /* 配置设备名称*/ + SETHOSTNAME = 7; + /* 没有绑定的时候要求AP 断开和AC 的连接,重启查询AC 的流程*/ + KICK_AP = 8; + /* 启动扫描*/ + START_SCAN = 9; + /* 下发认证*/ + AUTH = 10; + /* 下线用户*/ + LOGOUT = 11; + /* 下线用户*/ + REBOOTAP = 12; + + SHELL = 100; +} + +message WanConfig { + required string ipproto = 1; + optional string ip = 2; + optional string netmask = 3; + optional int32 metric = 4; + optional string gateway = 5; + optional string dns1 = 6; + optional string dns2 = 7; +} + +message WlanConfig +{ + required RadioBand band = 1; + required string ssid = 2; + required int32 gbk_enable = 3 [default = 0]; + required string encryption = 4; + optional string key = 5; + required int32 disabled = 6 [default = 0]; + + required int32 vlan = 10 [default = 0]; + required int32 maxsta = 11 [default = 0]; + required int32 rejrssi = 12 [default = -85]; + required int32 wmm = 13 [default = 1]; + required int32 isolate = 14 [default = 0]; + required int32 hide = 15 [default = 0]; + required int32 ieee80211r = 22 [default = 0]; + optional int32 auth_type= 25; /* 认证类型,将认证方式和ssid 关联*/ +} + +message PingWatchdog { + required int32 enable = 1; + optional string target = 2; + optional int32 ping_interval = 3; + optional int32 ping_failures = 4; + optional int32 ping_timeout = 5; + optional int32 ping_watchdog_action = 6 [default = 3]; +} + +message CMD { + required CMDType type = 1; + optional string args = 2; +} + +message Echo { + required string sn = 1; + required string product_name = 2; + /* 标识设备的唯一MAC */ + optional string mac = 3; + optional string board = 4; + optional string hostname = 5; + /* 运行时间*/ + optional string uptime = 6; + optional uint64 uptime_sec = 61; + + optional string version = 7; + required APMode apmode = 8 [default = FIT_AP]; + + /* 是否是第一次连接(要求下发配置) */ + required int32 newconnect = 9 [default = 0]; + + /* 关键配置的MD5 值*/ + optional string apnetwork_md5 = 10; + + optional string country = 11; + + /* CPU 占用率*/ + optional string cpu = 12; + + /* 是否云端管理的*/ + optional int32 is_on_cloud = 13 [default = 0]; + optional string username = 14; + /* 通过设备的上下行总流量统计*/ + optional uint64 uploadspeed = 21; + optional uint64 downloadspeed = 22; + optional uint64 uploadbytes = 23; + optional uint64 downloadbytes = 24; + + required string acaddr = 25; + + required ManageInterface mif = 50; /* 接口信息*/ + repeated RadioInfo radioinfo = 51; /* 射频信息*/ + optional WanConfig lanconfig = 52; /* lan 口配置*/ + optional PingWatchdog pingwatchdog = 53; /* Ping 看门狗*/ + repeated WlanConfig ssids = 54; /* ssid 配置*/ + + optional int32 iptvSupport = 70; + optional int32 iptvEnable = 71; + + /* 假设所有的CPE 都是单频的,单频2.4 或单频5G */ + /* 增加一个CPE 专用的信息上报,信道列表*/ + optional string cpeChannelsJson = 100; +} + +message StaInfo { + required string mac = 2; + optional string ip = 3; + required int32 signal = 4; + required int32 noise = 5; + required int32 snr = 6; + required string txrate = 7; + required string rxrate = 8; +} + +message WlanInfo { + optional string ssid = 1; + repeated StaInfo stas = 2; +} + +message RadioInfo { + required RadioBand band = 1; + repeated WlanInfo wlaninfo = 2; + + /* 基础三属性*/ + required RadioHTMode htmode = 3 [default = RHT_20]; + required uint32 txpower = 4 [default = 0]; + required uint32 channel = 5 [default = 0]; + + /* 其他属性*/ + optional int32 signal = 20; + optional int32 noise = 21; + optional string bitrate = 22; + + /* 增加字段*/ + optional int32 maxsta = 23 [default = 0]; + optional int32 rejrssi = 24 [default = -85]; + optional string country = 25; + optional int32 enable_fils = 26 [default = 1]; + optional string mac = 27; +} + +message ManageInterface { + required string ifname = 1; + optional string ip = 2; + optional string mac = 3; + optional string netmask = 4; + optional string gateway = 5; + optional string dns1= 6; + optional string dns2= 7; + optional string ipproto = 8; // dhcp static pppoe +} diff --git a/src/internal/mqtt/server.go b/src/internal/mqtt/server.go new file mode 100644 index 0000000..6f92b02 --- /dev/null +++ b/src/internal/mqtt/server.go @@ -0,0 +1,222 @@ +package mqtt + +import ( + "bytes" + "fmt" + "log/slog" + + "github.com/golang/protobuf/proto" + mqtt_server "github.com/mochi-mqtt/server/v2" + "github.com/mochi-mqtt/server/v2/hooks/auth" + "github.com/mochi-mqtt/server/v2/listeners" + "github.com/mochi-mqtt/server/v2/packets" + + "ac/internal/context" + "ac/internal/logger" + "ac/internal/mqtt/message" + "ac/pkg/app" +) + +type Server struct { + app.App + + mqttServer *mqtt_server.Server +} + +var mqttServer *mqtt_server.Server + +func NewServer(ac app.App) (*Server, error) { + server := mqtt_server.New(&mqtt_server.Options{ + Logger: slog.New(slog.NewTextHandler(logger.Log.Out, &slog.HandlerOptions{ + Level: slog.LevelDebug, + })), + InlineClient: true, // you must enable inline client to use direct publishing and subscribing. + }) + + _ = server.AddHook(new(auth.AllowHook), nil) + tcp := listeners.NewTCP(listeners.Config{ + ID: "t1", + Address: ":5247", + }) + err := server.AddListener(tcp) + if err != nil { + logger.MqttLog.Fatal(err) + } + + // Add ac hook (AcHook) to the server + err = server.AddHook(new(AcHook), &AcHookOptions{ + Server: server, + }) + + if err != nil { + logger.MqttLog.Fatal(err) + } + + mqttServer = server + + return &Server{ac, server}, nil +} + +// Options contains configuration settings for the hook. +type AcHookOptions struct { + Server *mqtt_server.Server +} + +type AcHook struct { + mqtt_server.HookBase + config *AcHookOptions +} + +func (h *AcHook) ID() string { + return "events-ac" +} + +func (h *AcHook) Provides(b byte) bool { + return bytes.Contains([]byte{ + mqtt_server.OnConnect, + mqtt_server.OnDisconnect, + mqtt_server.OnSubscribed, + mqtt_server.OnUnsubscribed, + mqtt_server.OnPublished, + mqtt_server.OnPublish, + }, []byte{b}) +} + +func (h *AcHook) Init(config any) error { + h.Log.Info("initialised") + if _, ok := config.(*AcHookOptions); !ok && config != nil { + return mqtt_server.ErrInvalidConfigType + } + + h.config = config.(*AcHookOptions) + if h.config.Server == nil { + return mqtt_server.ErrInvalidConfigType + } + return nil +} + +// subscribeCallback handles messages for subscribed topics +func (h *AcHook) subscribeCallback(cl *mqtt_server.Client, sub packets.Subscription, pk packets.Packet) { + h.Log.Info("hook subscribed message", "client", cl.ID, "topic", pk.TopicName) +} + +func (h *AcHook) OnConnect(cl *mqtt_server.Client, pk packets.Packet) error { + h.Log.Info("client connected", "client", cl.ID) + + // Example demonstrating how to subscribe to a topic within the hook. + h.config.Server.Subscribe("hook/direct/publish", 1, h.subscribeCallback) + + // Example demonstrating how to publish a message within the hook + err := h.config.Server.Publish("hook/direct/publish", []byte("packet hook message"), false, 0) + if err != nil { + h.Log.Error("hook.publish", "error", err) + } + + acSelf := context.GetSelf() + ap, ok := acSelf.ApFindByClientId(cl.ID) + if ok { + acSelf.DeleteAp(ap.Client) + } + logger.MqttLog.Infof("Create a new Client for: %s", cl.ID) + ap = acSelf.NewAp(cl) + + return nil +} + +func (h *AcHook) OnDisconnect(cl *mqtt_server.Client, err error, expire bool) { + if err != nil { + h.Log.Info("client disconnected", "client", cl.ID, "expire", expire, "error", err) + } else { + h.Log.Info("client disconnected", "client", cl.ID, "expire", expire) + } + + context.GetSelf().DeleteAp(cl) +} + +func (h *AcHook) OnSubscribed(cl *mqtt_server.Client, pk packets.Packet, reasonCodes []byte) { + h.Log.Info(fmt.Sprintf("subscribed qos=%v", reasonCodes), "client", cl.ID, "filters", pk.Filters) +} + +func (h *AcHook) OnUnsubscribed(cl *mqtt_server.Client, pk packets.Packet) { + h.Log.Info("unsubscribed", "client", cl.ID, "filters", pk.Filters) +} + +func (h *AcHook) OnPublish(cl *mqtt_server.Client, pk packets.Packet) (packets.Packet, error) { + h.Log.Info("received from client", "client", cl.ID, "payload", string(pk.Payload)) + + if cl.ID == "inline" { + return pk, nil + } + + acSelf := context.GetSelf() + ap, ok := acSelf.ApFindByClient(cl) + if !ok { + logger.MqttLog.Infof("Create a new Client for: %s", cl.ID) + ap = acSelf.NewAp(cl) + } + + if pk.TopicName == "AP/echo" { + var unmarshaledEcho message.Echo + err := proto.Unmarshal(pk.Payload, &unmarshaledEcho) + if err != nil { + logger.MqttLog.Errorf("Unmarshal to struct error: %v", err) + } else { + logger.MqttLog.Infof("received echo: %+v", &unmarshaledEcho) + ap.LastEcho = &unmarshaledEcho + } + } + + return pk, nil +} + +func (h *AcHook) OnPublished(cl *mqtt_server.Client, pk packets.Packet) { + h.Log.Info("published to client", "client", cl.ID, "payload", string(pk.Payload)) +} + +func SendCmdReboot(apSn string) { + var cmd message.CMD + cmd.Type = new(message.CMDType) + *cmd.Type = message.CMDType_REBOOT + encoded, err := proto.Marshal(&cmd) + if err != nil { + logger.MqttLog.Errorf("Encode to protobuf data error: %v", err) + } else { + topic := "AC/" + apSn + "/M_cmd" + err := mqttServer.Publish(topic, encoded, false, 2) + if err != nil { + logger.MqttLog.Error("publish", "error", err) + } + } +} + +func SendCmdKickUser(apSn, staMac string) { + var cmd message.CMD + cmd.Type = new(message.CMDType) + *cmd.Type = message.CMDType_KICK_USER + cmd.Args = new(string) + *cmd.Args = staMac + encoded, err := proto.Marshal(&cmd) + if err != nil { + logger.MqttLog.Errorf("Encode to protobuf data error: %v", err) + } else { + topic := "AC/" + apSn + "/M_cmd" + err := mqttServer.Publish(topic, encoded, false, 2) + if err != nil { + logger.MqttLog.Error("publish", "error", err) + } + } +} + +func (s *Server)Run() error { + logger.MqttLog.Infof("Start MQTT server") + return s.mqttServer.Serve() +} + +func (s *Server)Stop() { + if s.mqttServer != nil { + logger.MqttLog.Infof("Stop MQTT server") + if err := s.mqttServer.Close(); err != nil { + logger.MqttLog.Errorf("Could not close MQTT server: %#v", err) + } + } +} diff --git a/src/internal/telnet/handler.go b/src/internal/telnet/handler.go new file mode 100755 index 0000000..72d6d5f --- /dev/null +++ b/src/internal/telnet/handler.go @@ -0,0 +1,147 @@ +package telnet + +import ( + "fmt" + "time" + + "ac/internal/context" + grpcClient "ac/internal/grpc_client" + "ac/internal/mqtt" + "ac/internal/mqtt/message" + "ac/internal/version" +) + +const prompt string = "AC> " + +const help_menu string = +"\033[2J\033[1;1HAVAILABLE COMMANDS\n" + +"==============================================================================\n" + +"| Command | Remark |\n" + +"==============================================================================\n" + +"| help | Help page. |\n" + +"| date | Current date. |\n" + +"| list ver | Display version information. |\n" + +"| list ap | List all APs. |\n" + +"| list subs | List all wifi subscriber data. |\n" + +"| kick #apSn #staMac | Kick the STA specified by mac. |\n" + +"| reboot #apSn | Reboot the AP specified by SN. |\n" + +"| debug level error/warn/info/debug/trace | Set debug level. |\n" + +"| q or quit | Quit. |\n" + +"==============================================================================\n" + +func HandleTelnetRequest(cmd []string) string { + var response string + var opr, obj, val string + + if len(cmd) > 0 { + opr = cmd[0] + if len(cmd) > 1 { + obj = cmd[1] + if len(cmd) > 2 { + val = cmd[2] + } + } + } + + switch opr { + case "date": + response = time.Now().String() + "\n" + case "list": + switch obj { + case "ver": + response = version.GetVersionInfo() + "\n" + case "ap": + response = list_ap() + case "subs": + response = list_subs() + /*case "mac": + response = list_mac(val)*/ + default: + response = "COMMAND NOT FOUND\n" + } + case "kick": + mqtt.SendCmdKickUser(obj, val) + response = "COMMAND OK\n" + case "reboot": + mqtt.SendCmdReboot(obj) + response = "COMMAND OK\n" + default: + response = "COMMAND NOT FOUND\n" + } + return response +} + +func list_ap() string { + response := fmt.Sprintf("%-5s %-2s %-14s %-4s %-4s %-13s %-15s %-3s\n", "型号", "设备名称", "序列号", "工作模式", "接入方式", "IP地址", "MAC地址", "已运行") + context.GetSelf().ApPool.Range(func(key, value interface{}) bool { + ap := value.(*context.Ap) + if ap.LastEcho != nil { + response += fmt.Sprintf("%-7s %-8s %-17s %-8s %-8s %-15s %-17s %-6s\n", + ap.LastEcho.GetProductName(), ap.LastEcho.GetHostname(), ap.LastEcho.GetSn(), message.APMode_name[int32(ap.LastEcho.GetApmode())], + ap.LastEcho.Mif.GetIpproto(), ap.LastEcho.Mif.GetIp(), ap.LastEcho.Mif.GetMac(), ap.LastEcho.GetUptime()) + } + return true + }) + + return response +} + +func list_subs() string { + response := fmt.Sprintf("%-13s %-15s %-8s %-2s %-15s %-6s %-17s %-7s %-4s %-4s %-4s\n", "IP地址", "MAC地址", "主机名", "频段", "所属AP", "所属AP名称", "AP MAC", "无线名称", "信号强度", "接收速率", "发射速率") + context.GetSelf().ApPool.Range(func(key, value interface{}) bool { + ap := value.(*context.Ap) + if ap.LastEcho != nil { + response += buildStaInfo(ap.LastEcho) + } + return true + }) + + return response +} + +func buildStaInfo(echo *message.Echo) string { + var response string + + sn := echo.GetSn() // 所属AP + apname := echo.GetHostname() // 所属AP名称 + apmac := echo.GetMac() // AP MAC + + radioinfos := echo.GetRadioinfo() + if radioinfos == nil { + return "" + } + + for _, radioinfo := range radioinfos { + var band string + switch radioinfo.GetBand() { + case message.RadioBand_RB_2G: + band = "2.4G" + case message.RadioBand_RB_5G: + band = "5G" + } + wlaninfos := radioinfo.GetWlaninfo() + if wlaninfos == nil { + continue + } + for _, wlaninfo := range wlaninfos { + ssid := wlaninfo.GetSsid() + + stas := wlaninfo.GetStas() + if stas == nil { + continue + } + for _, sta := range stas { + mac := sta.GetMac() + signal := sta.GetSignal() + rxrate := sta.GetRxrate() + txrate := sta.GetTxrate() + //ip, hostname := getinfofromdhcp(mac) + ip, hostname := grpcClient.GetStaInfo(mac) + response += fmt.Sprintf("%-15s %-17s %-11s %-4s %-17s %-10s %-17s %-11s %-4ddBm %-8s %-8s\n", + ip, mac, hostname, band, sn, apname, apmac, ssid, signal, rxrate, txrate) + } + } + } + + return response +} diff --git a/src/internal/telnet/tcp.go b/src/internal/telnet/tcp.go new file mode 100755 index 0000000..c293a0a --- /dev/null +++ b/src/internal/telnet/tcp.go @@ -0,0 +1,100 @@ +package telnet + +import ( + "fmt" + "net" + "strings" + "time" +) + +var listener *net.TCPListener +var clientNum int + +// Server - Init TCP Server +func Run(addrStr string) { + addr := fmt.Sprintf("[%s]:4100", addrStr) + tcpAddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + fmt.Println("[Telnet] net.ResolveTCPAddr fail:", addr) + return + } + listener, err := net.ListenTCP("tcp", tcpAddr) + if err != nil { + fmt.Println("[Telnet] failed to listen:", err) + return + } + fmt.Println("[Telnet] Listen on", addr) + + go func() { + for { + conn, err := listener.Accept() + if err != nil { + fmt.Println(err.Error()) + continue + } else if clientNum >= 9 { + fmt.Println("too many telnet request connection") + conn.Close() + continue + } + + clientNum++ + fmt.Println("[Telnet] A new Connection", clientNum) + fmt.Println("[Telnet] TCP Accept from:", conn.RemoteAddr().String()) + + go start(conn) + } + }() +} + +// Start - Start TCP read channel +func start(conn net.Conn) { + defer closeConnection(conn) + + conn.Write([]byte(help_menu)) + conn.Write([]byte(prompt)) + for { + buffer := make([]byte, 128) + conn.SetReadDeadline(time.Now().Add(time.Minute*10)) + _, err := conn.Read(buffer) + if err != nil { + fmt.Println("[Telnet] Error", err) + break + } + buf := string(buffer) + pos := strings.Index(buf, "\n") + if pos < 0 || pos > 127 { + break + } + cmd := buf[:pos] + + sep := strings.Fields(cmd) + if len(sep) <= 0 { + conn.Write([]byte(prompt)) + continue + } + if sep[0] == "help" { + conn.Write([]byte(help_menu)) + conn.Write([]byte(prompt)) + continue + } + if sep[0] == "q" || sep[0] == "quit" { + break + } + + rsp := HandleTelnetRequest(sep) + conn.Write([]byte(rsp)) + conn.Write([]byte(prompt)) + } +} + +func closeConnection(conn net.Conn) { + conn.Close() + clientNum-- + fmt.Printf("[Telnet] Now, %d connections is alive.\n", clientNum) +} + +func Stop() { + if listener != nil { + listener.Close() + } +} diff --git a/src/internal/version/version.go b/src/internal/version/version.go new file mode 100644 index 0000000..5291ff9 --- /dev/null +++ b/src/internal/version/version.go @@ -0,0 +1,44 @@ +package version + +import ( + "fmt" + "runtime" +) + +var ( + VERSION string + COMMIT_HASH string + COMMIT_TIME string +) + +func GetVersion() string { + return VERSION +} + +func GetVersionAndHash() string { + return VERSION + " (" + COMMIT_HASH + ")" +} + +func GetVersionInfo() string { + if VERSION != "" { + return fmt.Sprintf( + "AC version: %s"+ + "\ncommit hash: %s"+ + "\ncommit time: %s"+ + "\ngo version: %s %s/%s", + VERSION, + COMMIT_HASH, + COMMIT_TIME, + runtime.Version(), + runtime.GOOS, + runtime.GOARCH, + ) + } else { + return fmt.Sprintf( + "Not specify ldflags (which link version) during go build\ngo version: %s %s/%s", + runtime.Version(), + runtime.GOOS, + runtime.GOARCH, + ) + } +} diff --git a/src/pkg/app/app.go b/src/pkg/app/app.go new file mode 100644 index 0000000..edeff29 --- /dev/null +++ b/src/pkg/app/app.go @@ -0,0 +1,16 @@ +package app + +import ( + ac_context "ac/internal/context" + "ac/pkg/factory" +) + +type App interface { + SetLogLevel(level string) + + Start() + Terminate() + + Context() *ac_context.ACContext + Config() *factory.Config +} diff --git a/src/pkg/factory/config.go b/src/pkg/factory/config.go new file mode 100644 index 0000000..5a8308c --- /dev/null +++ b/src/pkg/factory/config.go @@ -0,0 +1,71 @@ +/* + * AC Configuration Factory + */ + +package factory + +import ( + "fmt" + "sync" + + "github.com/asaskevich/govalidator" + "github.com/davecgh/go-spew/spew" + + "ac/internal/logger" +) + +const ( + AcDefaultConfigPath = "/usr/local/etc/ac/ac.yaml" + CapwapDefaultPort = 5246 + MqttDefaultPort = 5247 +) + +type Config struct { + DebugLevel string `yaml:"debugLevel" valid:"required,in(trace|debug|info|warn|error|fatal|panic)"` + CapwapAddr string `yaml:"capwapAddr,omitempty" valid:"required,host"` + sync.RWMutex +} + +func (c *Config) Validate() (bool, error) { + if _, err := govalidator.ValidateStruct(c); err != nil { + return false, appendInvalid(err) + } + + return true, nil +} + +func appendInvalid(err error) error { + var errs govalidator.Errors + + if err == nil { + return nil + } + + es := err.(govalidator.Errors).Errors() + for _, e := range es { + errs = append(errs, fmt.Errorf("Invalid %w", e)) + } + + return error(errs) +} + +func (c *Config) Print() { + spew.Config.Indent = "\t" + str := spew.Sdump(c) + logger.CfgLog.Infof("==================================================") + logger.CfgLog.Infof("%s", str) + logger.CfgLog.Infof("==================================================") +} + +func (c *Config) SetLogLevel(level string) { + c.Lock() + defer c.Unlock() + + c.DebugLevel = level +} + +func (c *Config) GetLogLevel() string { + c.RLock() + defer c.RUnlock() + return c.DebugLevel +} diff --git a/src/pkg/factory/factory.go b/src/pkg/factory/factory.go new file mode 100644 index 0000000..ae5037b --- /dev/null +++ b/src/pkg/factory/factory.go @@ -0,0 +1,48 @@ +/* + * AC Configuration Factory + */ + +package factory + +import ( + "fmt" + "os" + + "github.com/asaskevich/govalidator" + "gopkg.in/yaml.v2" + + "ac/internal/logger" +) + +var AcConfig *Config + +// TODO: Support configuration update from REST api +func InitConfigFactory(cfg *Config) error { + if content, err := os.ReadFile(AcDefaultConfigPath); err != nil { + return fmt.Errorf("[Factory] %+v", err) + } else { + logger.CfgLog.Infof("Read config from [%s]", AcDefaultConfigPath) + if yamlErr := yaml.Unmarshal(content, cfg); yamlErr != nil { + return fmt.Errorf("[Factory] %+v", yamlErr) + } + } + + return nil +} + +func ReadConfig() (*Config, error) { + cfg := &Config{} + if err := InitConfigFactory(cfg); err != nil { + return nil, fmt.Errorf("ReadConfig [%s] Error: %+v", AcDefaultConfigPath, err) + } + if _, err := cfg.Validate(); err != nil { + validErrs := err.(govalidator.Errors).Errors() + for _, validErr := range validErrs { + logger.CfgLog.Errorf("%+v", validErr) + } + logger.CfgLog.Errorf("[-- PLEASE REFER TO SAMPLE CONFIG FILE COMMENTS --]") + return nil, fmt.Errorf("Config validate Error") + } + + return cfg, nil +} diff --git a/src/pkg/service/init.go b/src/pkg/service/init.go new file mode 100644 index 0000000..3f817e2 --- /dev/null +++ b/src/pkg/service/init.go @@ -0,0 +1,129 @@ +package service + +import ( + "context" + "runtime/debug" + "sync" + + "github.com/sirupsen/logrus" + + "ac/internal/capwap" + capwap_service "ac/internal/capwap/service" + ac_context "ac/internal/context" + grpcClient "ac/internal/grpc_client" + "ac/internal/logger" + "ac/internal/mqtt" + "ac/internal/telnet" + "ac/pkg/app" + "ac/pkg/factory" +) + +var AC app.App + +type AcApp struct { + app.App + + cfg *factory.Config + acCtx *ac_context.ACContext + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup + + mqttServer *mqtt.Server +} + +func NewApp(ctx context.Context, cfg *factory.Config) (*AcApp, error) { + ac := &AcApp{ + cfg: cfg, + } + ac.SetLogLevel(cfg.GetLogLevel()) + + ac.ctx, ac.cancel = context.WithCancel(ctx) + ac.acCtx = ac_context.GetSelf() + + var err error + if ac.mqttServer, err = mqtt.NewServer(ac); err != nil { + return nil, err + } + + AC = ac + + return ac, nil +} + +func (a *AcApp) SetLogLevel(level string) { + lvl, err := logrus.ParseLevel(level) + if err != nil { + logger.MainLog.Warnf("Log level [%s] is invalid", level) + return + } + + logger.MainLog.Infof("Log level is set to [%s]", level) + if lvl == logger.Log.GetLevel() { + return + } + + a.cfg.SetLogLevel(level) + logger.Log.SetLevel(lvl) +} + +func (a *AcApp) Start() { + self := a.Context() + ac_context.InitAcContext(self) + + capwap_service.Run(self.CapwapAddr, capwap.HandleMessage) + + logger.InitLog.Infoln("Server started") + + a.wg.Add(1) + go a.listenShutdownEvent() + + telnet.Run("127.0.0.1") + + grpcClient.ConnectToServer("127.0.0.1", 50051) + + if err := a.mqttServer.Run(); err != nil { + logger.MainLog.Fatalf("Run MQTT server failed: %+v", err) + } + a.WaitRoutineStopped() +} + +// Used in AC planned removal procedure +func (a *AcApp) Terminate() { + a.cancel() +} + +func (a *AcApp) Config() *factory.Config { + return a.cfg +} + +func (a *AcApp) Context() *ac_context.ACContext { + return a.acCtx +} + +func (a *AcApp) CancelContext() context.Context { + return a.ctx +} + +func (a *AcApp) listenShutdownEvent() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.MainLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + a.wg.Done() + }() + + <-a.ctx.Done() + a.terminateProcedure() +} + +func (a *AcApp) WaitRoutineStopped() { + a.wg.Wait() + logger.MainLog.Infof("AC App is terminated") +} + +func (a *AcApp) terminateProcedure() { + logger.MainLog.Infof("Terminating AC...") + capwap_service.Stop() +}