Victory!
Signed-off-by: Solomon Hykes <solomon@docker.com>
| ... | ... |
@@ -1194,7 +1194,7 @@ func ServeFd(addr string, handle http.Handler) error {
|
| 1194 | 1194 |
chErrors := make(chan error, len(ls)) |
| 1195 | 1195 |
|
| 1196 | 1196 |
// We don't want to start serving on these sockets until the |
| 1197 |
- // "initserver" job has completed. Otherwise required handlers |
|
| 1197 |
+ // daemon is initialized and installed. Otherwise required handlers |
|
| 1198 | 1198 |
// won't be ready. |
| 1199 | 1199 |
<-activationLock |
| 1200 | 1200 |
|
| ... | ... |
@@ -11,7 +11,6 @@ import ( |
| 11 | 11 |
"github.com/docker/docker/events" |
| 12 | 12 |
"github.com/docker/docker/pkg/parsers/kernel" |
| 13 | 13 |
"github.com/docker/docker/registry" |
| 14 |
- "github.com/docker/docker/server" |
|
| 15 | 14 |
) |
| 16 | 15 |
|
| 17 | 16 |
func Register(eng *engine.Engine) error {
|
| ... | ... |
@@ -54,9 +53,6 @@ func remote(eng *engine.Engine) error {
|
| 54 | 54 |
// These components should be broken off into plugins of their own. |
| 55 | 55 |
// |
| 56 | 56 |
func daemon(eng *engine.Engine) error {
|
| 57 |
- if err := eng.Register("initserver", server.InitServer); err != nil {
|
|
| 58 |
- return err |
|
| 59 |
- } |
|
| 60 | 57 |
return eng.Register("init_networkdriver", bridge.InitDriver)
|
| 61 | 58 |
} |
| 62 | 59 |
|
| ... | ... |
@@ -135,6 +135,12 @@ func (daemon *Daemon) Install(eng *engine.Engine) error {
|
| 135 | 135 |
return err |
| 136 | 136 |
} |
| 137 | 137 |
} |
| 138 |
+ if err := daemon.Repositories().Install(eng); err != nil {
|
|
| 139 |
+ return err |
|
| 140 |
+ } |
|
| 141 |
+ // FIXME: this hack is necessary for legacy integration tests to access |
|
| 142 |
+ // the daemon object. |
|
| 143 |
+ eng.Hack_SetGlobalVar("httpapi.daemon", daemon)
|
|
| 138 | 144 |
return nil |
| 139 | 145 |
} |
| 140 | 146 |
|
| ... | ... |
@@ -2,7 +2,6 @@ package daemonconfig |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"github.com/docker/docker/daemon/networkdriver" |
| 5 |
- "github.com/docker/docker/engine" |
|
| 6 | 5 |
"net" |
| 7 | 6 |
) |
| 8 | 7 |
|
| ... | ... |
@@ -34,46 +33,6 @@ type Config struct {
|
| 34 | 34 |
Sockets []string |
| 35 | 35 |
} |
| 36 | 36 |
|
| 37 |
-// ConfigFromJob creates and returns a new DaemonConfig object |
|
| 38 |
-// by parsing the contents of a job's environment. |
|
| 39 |
-func ConfigFromJob(job *engine.Job) *Config {
|
|
| 40 |
- config := &Config{
|
|
| 41 |
- Pidfile: job.Getenv("Pidfile"),
|
|
| 42 |
- Root: job.Getenv("Root"),
|
|
| 43 |
- AutoRestart: job.GetenvBool("AutoRestart"),
|
|
| 44 |
- EnableIptables: job.GetenvBool("EnableIptables"),
|
|
| 45 |
- EnableIpForward: job.GetenvBool("EnableIpForward"),
|
|
| 46 |
- BridgeIP: job.Getenv("BridgeIP"),
|
|
| 47 |
- BridgeIface: job.Getenv("BridgeIface"),
|
|
| 48 |
- DefaultIp: net.ParseIP(job.Getenv("DefaultIp")),
|
|
| 49 |
- InterContainerCommunication: job.GetenvBool("InterContainerCommunication"),
|
|
| 50 |
- GraphDriver: job.Getenv("GraphDriver"),
|
|
| 51 |
- ExecDriver: job.Getenv("ExecDriver"),
|
|
| 52 |
- EnableSelinuxSupport: job.GetenvBool("EnableSelinuxSupport"),
|
|
| 53 |
- } |
|
| 54 |
- if graphOpts := job.GetenvList("GraphOptions"); graphOpts != nil {
|
|
| 55 |
- config.GraphOptions = graphOpts |
|
| 56 |
- } |
|
| 57 |
- |
|
| 58 |
- if dns := job.GetenvList("Dns"); dns != nil {
|
|
| 59 |
- config.Dns = dns |
|
| 60 |
- } |
|
| 61 |
- if dnsSearch := job.GetenvList("DnsSearch"); dnsSearch != nil {
|
|
| 62 |
- config.DnsSearch = dnsSearch |
|
| 63 |
- } |
|
| 64 |
- if mtu := job.GetenvInt("Mtu"); mtu != 0 {
|
|
| 65 |
- config.Mtu = mtu |
|
| 66 |
- } else {
|
|
| 67 |
- config.Mtu = GetDefaultNetworkMtu() |
|
| 68 |
- } |
|
| 69 |
- config.DisableNetwork = config.BridgeIface == DisableNetworkBridge |
|
| 70 |
- if sockets := job.GetenvList("Sockets"); sockets != nil {
|
|
| 71 |
- config.Sockets = sockets |
|
| 72 |
- } |
|
| 73 |
- |
|
| 74 |
- return config |
|
| 75 |
-} |
|
| 76 |
- |
|
| 77 | 37 |
func GetDefaultNetworkMtu() int {
|
| 78 | 38 |
if iface, err := networkdriver.GetDefaultRouteIface(); err == nil {
|
| 79 | 39 |
return iface.MTU |
| ... | ... |
@@ -7,8 +7,10 @@ import ( |
| 7 | 7 |
"net" |
| 8 | 8 |
|
| 9 | 9 |
"github.com/docker/docker/builtins" |
| 10 |
+ "github.com/docker/docker/daemon" |
|
| 10 | 11 |
_ "github.com/docker/docker/daemon/execdriver/lxc" |
| 11 | 12 |
_ "github.com/docker/docker/daemon/execdriver/native" |
| 13 |
+ "github.com/docker/docker/daemonconfig" |
|
| 12 | 14 |
"github.com/docker/docker/dockerversion" |
| 13 | 15 |
"github.com/docker/docker/engine" |
| 14 | 16 |
flag "github.com/docker/docker/pkg/mflag" |
| ... | ... |
@@ -46,27 +48,38 @@ func mainDaemon() {
|
| 46 | 46 |
// the http api so that connections don't fail while the daemon |
| 47 | 47 |
// is booting |
| 48 | 48 |
go func() {
|
| 49 |
- // Load plugin: httpapi |
|
| 50 |
- job := eng.Job("initserver")
|
|
| 51 |
- // include the variable here too, for the server config |
|
| 52 |
- job.Setenv("Pidfile", *pidfile)
|
|
| 53 |
- job.Setenv("Root", *flRoot)
|
|
| 54 |
- job.SetenvBool("AutoRestart", *flAutoRestart)
|
|
| 55 |
- job.SetenvList("Dns", flDns.GetAll())
|
|
| 56 |
- job.SetenvList("DnsSearch", flDnsSearch.GetAll())
|
|
| 57 |
- job.SetenvBool("EnableIptables", *flEnableIptables)
|
|
| 58 |
- job.SetenvBool("EnableIpForward", *flEnableIpForward)
|
|
| 59 |
- job.Setenv("BridgeIface", *bridgeName)
|
|
| 60 |
- job.Setenv("BridgeIP", *bridgeIp)
|
|
| 61 |
- job.Setenv("DefaultIp", *flDefaultIp)
|
|
| 62 |
- job.SetenvBool("InterContainerCommunication", *flInterContainerComm)
|
|
| 63 |
- job.Setenv("GraphDriver", *flGraphDriver)
|
|
| 64 |
- job.SetenvList("GraphOptions", flGraphOpts.GetAll())
|
|
| 65 |
- job.Setenv("ExecDriver", *flExecDriver)
|
|
| 66 |
- job.SetenvInt("Mtu", *flMtu)
|
|
| 67 |
- job.SetenvBool("EnableSelinuxSupport", *flSelinuxEnabled)
|
|
| 68 |
- job.SetenvList("Sockets", flHosts.GetAll())
|
|
| 69 |
- if err := job.Run(); err != nil {
|
|
| 49 |
+ // FIXME: daemonconfig and CLI flag parsing should be directly integrated |
|
| 50 |
+ cfg := &daemonconfig.Config{
|
|
| 51 |
+ Pidfile: *pidfile, |
|
| 52 |
+ Root: *flRoot, |
|
| 53 |
+ AutoRestart: *flAutoRestart, |
|
| 54 |
+ EnableIptables: *flEnableIptables, |
|
| 55 |
+ EnableIpForward: *flEnableIpForward, |
|
| 56 |
+ BridgeIP: *bridgeIp, |
|
| 57 |
+ BridgeIface: *bridgeName, |
|
| 58 |
+ DefaultIp: net.ParseIP(*flDefaultIp), |
|
| 59 |
+ InterContainerCommunication: *flInterContainerComm, |
|
| 60 |
+ GraphDriver: *flGraphDriver, |
|
| 61 |
+ ExecDriver: *flExecDriver, |
|
| 62 |
+ EnableSelinuxSupport: *flSelinuxEnabled, |
|
| 63 |
+ GraphOptions: flGraphOpts.GetAll(), |
|
| 64 |
+ Dns: flDns.GetAll(), |
|
| 65 |
+ DnsSearch: flDnsSearch.GetAll(), |
|
| 66 |
+ Mtu: *flMtu, |
|
| 67 |
+ Sockets: flHosts.GetAll(), |
|
| 68 |
+ } |
|
| 69 |
+ // FIXME this should be initialized in NewDaemon or somewhere in daemonconfig. |
|
| 70 |
+ // Currently it is copy-pasted in `integration` to create test daemons that work. |
|
| 71 |
+ if cfg.Mtu == 0 {
|
|
| 72 |
+ cfg.Mtu = daemonconfig.GetDefaultNetworkMtu() |
|
| 73 |
+ } |
|
| 74 |
+ cfg.DisableNetwork = cfg.BridgeIface == daemonconfig.DisableNetworkBridge |
|
| 75 |
+ |
|
| 76 |
+ d, err := daemon.NewDaemon(cfg, eng) |
|
| 77 |
+ if err != nil {
|
|
| 78 |
+ log.Fatal(err) |
|
| 79 |
+ } |
|
| 80 |
+ if err := d.Install(eng); err != nil {
|
|
| 70 | 81 |
log.Fatal(err) |
| 71 | 82 |
} |
| 72 | 83 |
// after the daemon is done setting up we can tell the api to start |
| ... | ... |
@@ -75,7 +88,6 @@ func mainDaemon() {
|
| 75 | 75 |
log.Fatal(err) |
| 76 | 76 |
} |
| 77 | 77 |
}() |
| 78 |
- |
|
| 79 | 78 |
// TODO actually have a resolved graphdriver to show? |
| 80 | 79 |
log.Printf("docker daemon: %s %s; execdriver: %s; graphdriver: %s",
|
| 81 | 80 |
dockerversion.VERSION, |
| ... | ... |
@@ -202,7 +202,7 @@ func spawnHttpsDaemon(addr, cacert, cert, key string) *engine.Engine {
|
| 202 | 202 |
if err != nil {
|
| 203 | 203 |
t.Fatal(err) |
| 204 | 204 |
} |
| 205 |
- // FIXME: here we don't use NewTestEngine because it calls initserver with Autorestart=false, |
|
| 205 |
+ // FIXME: here we don't use NewTestEngine because it configures the daemon with Autorestart=false, |
|
| 206 | 206 |
// and we want to set it to true. |
| 207 | 207 |
|
| 208 | 208 |
eng := newTestEngine(t, true, root) |
| ... | ... |
@@ -100,7 +100,6 @@ func TestMergeConfigOnCommit(t *testing.T) {
|
| 100 | 100 |
|
| 101 | 101 |
func TestRestartKillWait(t *testing.T) {
|
| 102 | 102 |
eng := NewTestEngine(t) |
| 103 |
- srv := mkServerFromEngine(eng, t) |
|
| 104 | 103 |
runtime := mkDaemonFromEngine(eng, t) |
| 105 | 104 |
defer runtime.Nuke() |
| 106 | 105 |
|
| ... | ... |
@@ -138,9 +137,8 @@ func TestRestartKillWait(t *testing.T) {
|
| 138 | 138 |
} |
| 139 | 139 |
|
| 140 | 140 |
eng = newTestEngine(t, false, runtime.Config().Root) |
| 141 |
- srv = mkServerFromEngine(eng, t) |
|
| 142 | 141 |
|
| 143 |
- job = srv.Eng.Job("containers")
|
|
| 142 |
+ job = eng.Job("containers")
|
|
| 144 | 143 |
job.SetenvBool("all", true)
|
| 145 | 144 |
outs, err = job.Stdout.AddListTable() |
| 146 | 145 |
if err != nil {
|
| ... | ... |
@@ -155,7 +153,7 @@ func TestRestartKillWait(t *testing.T) {
|
| 155 | 155 |
} |
| 156 | 156 |
|
| 157 | 157 |
setTimeout(t, "Waiting on stopped container timedout", 5*time.Second, func() {
|
| 158 |
- job = srv.Eng.Job("wait", outs.Data[0].Get("Id"))
|
|
| 158 |
+ job = eng.Job("wait", outs.Data[0].Get("Id"))
|
|
| 159 | 159 |
if err := job.Run(); err != nil {
|
| 160 | 160 |
t.Fatal(err) |
| 161 | 161 |
} |
| ... | ... |
@@ -164,7 +162,6 @@ func TestRestartKillWait(t *testing.T) {
|
| 164 | 164 |
|
| 165 | 165 |
func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
| 166 | 166 |
eng := NewTestEngine(t) |
| 167 |
- srv := mkServerFromEngine(eng, t) |
|
| 168 | 167 |
defer mkDaemonFromEngine(eng, t).Nuke() |
| 169 | 168 |
|
| 170 | 169 |
config, hostConfig, _, err := runconfig.Parse([]string{"-i", unitTestImageID, "/bin/cat"}, nil)
|
| ... | ... |
@@ -174,7 +171,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
| 174 | 174 |
|
| 175 | 175 |
id := createTestContainer(eng, config, t) |
| 176 | 176 |
|
| 177 |
- job := srv.Eng.Job("containers")
|
|
| 177 |
+ job := eng.Job("containers")
|
|
| 178 | 178 |
job.SetenvBool("all", true)
|
| 179 | 179 |
outs, err := job.Stdout.AddListTable() |
| 180 | 180 |
if err != nil {
|
| ... | ... |
@@ -227,7 +224,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
|
| 227 | 227 |
t.Fatal(err) |
| 228 | 228 |
} |
| 229 | 229 |
|
| 230 |
- job = srv.Eng.Job("containers")
|
|
| 230 |
+ job = eng.Job("containers")
|
|
| 231 | 231 |
job.SetenvBool("all", true)
|
| 232 | 232 |
outs, err = job.Stdout.AddListTable() |
| 233 | 233 |
if err != nil {
|
| ... | ... |
@@ -17,9 +17,9 @@ import ( |
| 17 | 17 |
|
| 18 | 18 |
"github.com/docker/docker/builtins" |
| 19 | 19 |
"github.com/docker/docker/daemon" |
| 20 |
+ "github.com/docker/docker/daemonconfig" |
|
| 20 | 21 |
"github.com/docker/docker/engine" |
| 21 | 22 |
"github.com/docker/docker/runconfig" |
| 22 |
- "github.com/docker/docker/server" |
|
| 23 | 23 |
"github.com/docker/docker/utils" |
| 24 | 24 |
) |
| 25 | 25 |
|
| ... | ... |
@@ -153,18 +153,6 @@ func getContainer(eng *engine.Engine, id string, t utils.Fataler) *daemon.Contai |
| 153 | 153 |
return c |
| 154 | 154 |
} |
| 155 | 155 |
|
| 156 |
-func mkServerFromEngine(eng *engine.Engine, t utils.Fataler) *server.Server {
|
|
| 157 |
- iSrv := eng.Hack_GetGlobalVar("httpapi.server")
|
|
| 158 |
- if iSrv == nil {
|
|
| 159 |
- panic("Legacy server field not set in engine")
|
|
| 160 |
- } |
|
| 161 |
- srv, ok := iSrv.(*server.Server) |
|
| 162 |
- if !ok {
|
|
| 163 |
- panic("Legacy server field in engine does not cast to *server.Server")
|
|
| 164 |
- } |
|
| 165 |
- return srv |
|
| 166 |
-} |
|
| 167 |
- |
|
| 168 | 156 |
func mkDaemonFromEngine(eng *engine.Engine, t utils.Fataler) *daemon.Daemon {
|
| 169 | 157 |
iDaemon := eng.Hack_GetGlobalVar("httpapi.daemon")
|
| 170 | 158 |
if iDaemon == nil {
|
| ... | ... |
@@ -191,13 +179,22 @@ func newTestEngine(t utils.Fataler, autorestart bool, root string) *engine.Engin |
| 191 | 191 |
// Load default plugins |
| 192 | 192 |
builtins.Register(eng) |
| 193 | 193 |
// (This is manually copied and modified from main() until we have a more generic plugin system) |
| 194 |
- job := eng.Job("initserver")
|
|
| 195 |
- job.Setenv("Root", root)
|
|
| 196 |
- job.SetenvBool("AutoRestart", autorestart)
|
|
| 197 |
- job.Setenv("ExecDriver", "native")
|
|
| 198 |
- // TestGetEnabledCors and TestOptionsRoute require EnableCors=true |
|
| 199 |
- job.SetenvBool("EnableCors", true)
|
|
| 200 |
- if err := job.Run(); err != nil {
|
|
| 194 |
+ cfg := &daemonconfig.Config{
|
|
| 195 |
+ Root: root, |
|
| 196 |
+ AutoRestart: autorestart, |
|
| 197 |
+ ExecDriver: "native", |
|
| 198 |
+ } |
|
| 199 |
+ // FIXME: this should be initialized in NewDaemon or somewhere in daemonconfig. |
|
| 200 |
+ // Currently it is copy-pasted from daemonMain() |
|
| 201 |
+ if cfg.Mtu == 0 {
|
|
| 202 |
+ cfg.Mtu = daemonconfig.GetDefaultNetworkMtu() |
|
| 203 |
+ } |
|
| 204 |
+ cfg.DisableNetwork = cfg.BridgeIface == daemonconfig.DisableNetworkBridge |
|
| 205 |
+ d, err := daemon.NewDaemon(cfg, eng) |
|
| 206 |
+ if err != nil {
|
|
| 207 |
+ t.Fatal(err) |
|
| 208 |
+ } |
|
| 209 |
+ if err := d.Install(eng); err != nil {
|
|
| 201 | 210 |
t.Fatal(err) |
| 202 | 211 |
} |
| 203 | 212 |
return eng |
| 4 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,62 +0,0 @@ |
| 1 |
-// DEPRECATION NOTICE. PLEASE DO NOT ADD ANYTHING TO THIS FILE. |
|
| 2 |
-// |
|
| 3 |
-// For additional commments see server/server.go |
|
| 4 |
-// |
|
| 5 |
-package server |
|
| 6 |
- |
|
| 7 |
-import ( |
|
| 8 |
- "github.com/docker/docker/daemon" |
|
| 9 |
- "github.com/docker/docker/daemonconfig" |
|
| 10 |
- "github.com/docker/docker/engine" |
|
| 11 |
-) |
|
| 12 |
- |
|
| 13 |
-func (srv *Server) handlerWrap(h engine.Handler) engine.Handler {
|
|
| 14 |
- return func(job *engine.Job) engine.Status {
|
|
| 15 |
- srv.tasks.Add(1) |
|
| 16 |
- defer srv.tasks.Done() |
|
| 17 |
- return h(job) |
|
| 18 |
- } |
|
| 19 |
-} |
|
| 20 |
- |
|
| 21 |
-// jobInitApi runs the remote api server `srv` as a daemon, |
|
| 22 |
-// Only one api server can run at the same time - this is enforced by a pidfile. |
|
| 23 |
-// The signals SIGINT, SIGQUIT and SIGTERM are intercepted for cleanup. |
|
| 24 |
-func InitServer(job *engine.Job) engine.Status {
|
|
| 25 |
- job.Logf("Creating server")
|
|
| 26 |
- cfg := daemonconfig.ConfigFromJob(job) |
|
| 27 |
- srv, err := NewServer(job.Eng, cfg) |
|
| 28 |
- if err != nil {
|
|
| 29 |
- return job.Error(err) |
|
| 30 |
- } |
|
| 31 |
- job.Eng.Hack_SetGlobalVar("httpapi.server", srv)
|
|
| 32 |
- job.Eng.Hack_SetGlobalVar("httpapi.daemon", srv.daemon)
|
|
| 33 |
- |
|
| 34 |
- for name, handler := range map[string]engine.Handler{} {
|
|
| 35 |
- if err := job.Eng.Register(name, srv.handlerWrap(handler)); err != nil {
|
|
| 36 |
- return job.Error(err) |
|
| 37 |
- } |
|
| 38 |
- } |
|
| 39 |
- // Install image-related commands from the image subsystem. |
|
| 40 |
- // See `graph/service.go` |
|
| 41 |
- if err := srv.daemon.Repositories().Install(job.Eng); err != nil {
|
|
| 42 |
- return job.Error(err) |
|
| 43 |
- } |
|
| 44 |
- // Install daemon-related commands from the daemon subsystem. |
|
| 45 |
- // See `daemon/` |
|
| 46 |
- if err := srv.daemon.Install(job.Eng); err != nil {
|
|
| 47 |
- return job.Error(err) |
|
| 48 |
- } |
|
| 49 |
- return engine.StatusOK |
|
| 50 |
-} |
|
| 51 |
- |
|
| 52 |
-func NewServer(eng *engine.Engine, config *daemonconfig.Config) (*Server, error) {
|
|
| 53 |
- daemon, err := daemon.NewDaemon(config, eng) |
|
| 54 |
- if err != nil {
|
|
| 55 |
- return nil, err |
|
| 56 |
- } |
|
| 57 |
- srv := &Server{
|
|
| 58 |
- Eng: eng, |
|
| 59 |
- daemon: daemon, |
|
| 60 |
- } |
|
| 61 |
- return srv, nil |
|
| 62 |
-} |
| 63 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,36 +0,0 @@ |
| 1 |
-// DEPRECATION NOTICE. PLEASE DO NOT ADD ANYTHING TO THIS FILE. |
|
| 2 |
-// |
|
| 3 |
-// server/server.go is deprecated. We are working on breaking it up into smaller, cleaner |
|
| 4 |
-// pieces which will be easier to find and test. This will help make the code less |
|
| 5 |
-// redundant and more readable. |
|
| 6 |
-// |
|
| 7 |
-// Contributors, please don't add anything to server/server.go, unless it has the explicit |
|
| 8 |
-// goal of helping the deprecation effort. |
|
| 9 |
-// |
|
| 10 |
-// Maintainers, please refuse patches which add code to server/server.go. |
|
| 11 |
-// |
|
| 12 |
-// Instead try the following files: |
|
| 13 |
-// * For code related to local image management, try graph/ |
|
| 14 |
-// * For code related to image downloading, uploading, remote search etc, try registry/ |
|
| 15 |
-// * For code related to the docker daemon, try daemon/ |
|
| 16 |
-// * For small utilities which could potentially be useful outside of Docker, try pkg/ |
|
| 17 |
-// * For miscalleneous "util" functions which are docker-specific, try encapsulating them |
|
| 18 |
-// inside one of the subsystems above. If you really think they should be more widely |
|
| 19 |
-// available, are you sure you can't remove the docker dependencies and move them to |
|
| 20 |
-// pkg? In last resort, you can add them to utils/ (but please try not to). |
|
| 21 |
- |
|
| 22 |
-package server |
|
| 23 |
- |
|
| 24 |
-import ( |
|
| 25 |
- "sync" |
|
| 26 |
- |
|
| 27 |
- "github.com/docker/docker/daemon" |
|
| 28 |
- "github.com/docker/docker/engine" |
|
| 29 |
-) |
|
| 30 |
- |
|
| 31 |
-type Server struct {
|
|
| 32 |
- sync.RWMutex |
|
| 33 |
- daemon *daemon.Daemon |
|
| 34 |
- Eng *engine.Engine |
|
| 35 |
- tasks sync.WaitGroup |
|
| 36 |
-} |