Files
natpass/code/client/app/program.go
T

157 lines
3.6 KiB
Go

package app
import (
"os"
rt "runtime"
"github.com/kardianos/service"
"github.com/lwch/logging"
"github.com/lwch/natpass/code/client/conn"
"github.com/lwch/natpass/code/client/dashboard"
"github.com/lwch/natpass/code/client/global"
"github.com/lwch/natpass/code/client/rule"
"github.com/lwch/natpass/code/client/rule/bench"
"github.com/lwch/natpass/code/client/rule/code"
"github.com/lwch/natpass/code/client/rule/shell"
"github.com/lwch/natpass/code/client/rule/vnc"
"github.com/lwch/natpass/code/network"
"github.com/lwch/runtime"
)
type program struct {
confDir string
cfg *global.Configure
conn *conn.Conn
}
func newProgram() *program {
return &program{}
}
func (p *program) setConfDir(dir string) *program {
p.confDir = dir
return p
}
func (p *program) setConfigure(cfg *global.Configure) *program {
p.cfg = cfg
return p
}
// Start main entry for service
func (p *program) Start(s service.Service) error {
go p.run()
return nil
}
// Stop stop service callback
func (*program) Stop(s service.Service) error {
return nil
}
func (p *program) run() {
// go func() {
// http.ListenAndServe(":9000", nil)
// }()
// initialize logging
stdout := true
if rt.GOOS == "windows" {
stdout = false
}
logging.SetSizeRotate(logging.SizeRotateConfig{
Dir: p.cfg.LogDir,
Name: "np-cli",
Size: int64(p.cfg.LogSize.Bytes()),
Rotate: p.cfg.LogRotate,
WriteStdout: stdout,
WriteFile: true,
})
defer logging.Flush()
// create connection and handshake
p.conn = conn.New(p.cfg)
// build rule manager
mgr := rule.New()
// add rules from configure file, wait http request from web browser
for _, t := range p.cfg.Rules {
switch t.Type {
case "shell":
sh := shell.New(t, p.cfg.ReadTimeout, p.cfg.WriteTimeout)
mgr.Add(sh)
go sh.Handle(p.conn)
case "vnc":
v := vnc.New(t, p.cfg.ReadTimeout, p.cfg.WriteTimeout)
mgr.Add(v)
go v.Handle(p.conn)
case "bench":
b := bench.New(t)
mgr.Add(b)
go b.Handle(p.conn)
case "code-server":
cs := code.New(t, p.cfg.ReadTimeout, p.cfg.WriteTimeout)
mgr.Add(cs)
go cs.Handle(p.conn)
}
}
// handle request from remote node
go func() {
for {
msg := <-p.conn.ChanUnknown()
var linkID string
switch msg.GetXType() {
case network.Msg_connect_req:
switch msg.GetCreq().GetXType() {
case network.ConnectRequest_shell:
// fork /bin/bash command and ack
p.shellCreate(mgr, p.conn, msg)
case network.ConnectRequest_vnc:
// fork np-cli vnc child process and ack
p.vncCreate(p.confDir, mgr, p.conn, msg)
case network.ConnectRequest_bench:
// bench handler response ok directly
p.benchCreate(p.confDir, mgr, p.conn, msg)
case network.ConnectRequest_code:
// fork code-server child process and ack
p.codeCreate(p.confDir, mgr, p.conn, msg)
}
default:
linkID = msg.GetLinkId()
}
// invalid message type, close channel directly
if len(linkID) > 0 {
p.conn.ChanClose(linkID)
logging.Error("link of %s not found, type=%s",
linkID, msg.GetXType().String())
continue
}
}
}()
// on disconnect message dispatcher, also to close the forked process
go func() {
for {
id := <-p.conn.ChanDisconnect()
mgr.OnDisconnect(id)
}
}()
if p.cfg.DashboardEnabled {
// if the dashboard is enabled, wait the connection close async
go func() {
p.conn.Wait()
logging.Flush()
os.Exit(1)
}()
// handle dashboard
db := dashboard.New(p.cfg, p.conn, mgr, Version)
runtime.Assert(db.ListenAndServe(p.cfg.DashboardListen, p.cfg.DashboardPort))
} else {
// wait the connection close
p.conn.Wait()
}
}