package server import ( "cwtch.im/cwtch/server/fetch" "cwtch.im/cwtch/server/listen" "cwtch.im/cwtch/server/metrics" "cwtch.im/cwtch/server/send" "cwtch.im/cwtch/server/storage" "git.openprivacy.ca/openprivacy/connectivity" "git.openprivacy.ca/openprivacy/connectivity/tor" "git.openprivacy.ca/openprivacy/libricochet-go/application" "git.openprivacy.ca/openprivacy/libricochet-go/channels" "git.openprivacy.ca/openprivacy/log" "os" "strconv" "time" ) // Server encapsulates a complete, compliant Cwtch server. type Server struct { app *application.RicochetApplication config Config metricsPack metrics.Monitors closed bool } // Run starts a server with the given privateKey // TODO: surface errors // TODO: handle HUP/KILL signals to exit and close Tor gracefully // TODO: handle user input to exit func (s *Server) Run(acn connectivity.ACN, serverConfig Config) { s.closed = false s.config = serverConfig cwtchserver := new(application.RicochetApplication) s.metricsPack.Start(cwtchserver, serverConfig.ConfigDir, s.config.ServerReporting.LogMetricsToFile) af := application.InstanceFactory{} af.Init() ms := new(storage.MessageStore) err := ms.Init(serverConfig.ConfigDir, s.config.MaxBufferLines, s.metricsPack.MessageCounter) if err != nil { log.Errorln(err) acn.Close() os.Exit(1) } af.AddHandler("im.cwtch.server.listen", func(rai *application.Instance) func() channels.Handler { return func() channels.Handler { cslc := new(listen.CwtchServerListenChannel) return cslc } }) af.AddHandler("im.cwtch.server.fetch", func(rai *application.Instance) func() channels.Handler { si := new(Instance) si.Init(rai, cwtchserver, ms) return func() channels.Handler { cssc := new(fetch.CwtchServerFetchChannel) cssc.Handler = si return cssc } }) af.AddHandler("im.cwtch.server.send", func(rai *application.Instance) func() channels.Handler { si := new(Instance) si.Init(rai, cwtchserver, ms) return func() channels.Handler { cssc := new(send.CwtchServerSendChannel) cssc.Handler = si return cssc } }) addressIdentity := tor.GetTorV3Hostname(s.config.PublicKey) cwtchserver.Init(acn, "cwtch server for "+addressIdentity, s.config.Identity(), af, new(application.AcceptAllContactManager)) port := strconv.Itoa(application.RicochetPort) log.Infof("cwtch server running on cwtch:%s\n", addressIdentity+".onion:"+port) s.app = cwtchserver for true { listenService, err := acn.Listen(s.config.PrivateKey, application.RicochetPort) if err != nil { log.Errorf("Listen() error setting up onion service: %v\n", err) } else { s.app.Run(listenService) } if s.closed { return } time.Sleep(5 * time.Second) } } // Shutdown kills the app closing all connections and freeing all goroutines func (s *Server) Shutdown() { s.closed = true s.app.Shutdown() s.metricsPack.Stop() }