func (s *Server) reconfigure(c engine.Config) error { dldir, err := filepath.Abs(c.DownloadDirectory) if err != nil { return fmt.Errorf("Invalid path") } c.DownloadDirectory = dldir if err := s.engine.Configure(c); err != nil { return err } b, _ := json.MarshalIndent(&c, "", " ") ioutil.WriteFile(s.ConfigPath, b, 0755) s.state.Config = c s.state.Update() return nil }
func (s *Server) Run(version string) error { tls := s.CertPath != "" || s.KeyPath != "" //poor man's XOR if tls && (s.CertPath == "" || s.KeyPath == "") { return fmt.Errorf("You must provide both key and cert paths") } s.state.Stats.Title = s.Title s.state.Stats.Version = version s.state.Stats.Runtime = strings.TrimPrefix(runtime.Version(), "go") s.state.Stats.Uptime = time.Now() //init maps s.state.Users = map[string]*realtime.User{} //will use a the local embed/ dir if it exists, otherwise will use the hardcoded embedded binaries s.files = http.HandlerFunc(s.serveFiles) s.static = ctstatic.FileSystemHandler() s.scraper = &scraper.Handler{Log: false} if err := s.scraper.LoadConfig(defaultSearchConfig); err != nil { log.Fatal(err) } s.state.SearchProviders = s.scraper.Config //share scraper config s.scraperh = http.StripPrefix("/search", s.scraper) s.engine = engine.New() //realtime s.rt = realtime.NewHandler() if err := s.rt.Add("state", &s.state); err != nil { log.Fatalf("State object not syncable: %s", err) } //realtime user events go func() { for user := range s.rt.UserEvents() { if user.Connected { s.state.Users[user.ID] = user } else { delete(s.state.Users, user.ID) } s.state.Update() } }() //configure engine c := engine.Config{ DownloadDirectory: "./downloads", EnableUpload: true, AutoStart: true, } if _, err := os.Stat(s.ConfigPath); err == nil { if b, err := ioutil.ReadFile(s.ConfigPath); err != nil { return fmt.Errorf("Read configuration error: %s", err) } else if len(b) == 0 { //ignore empty file } else if err := json.Unmarshal(b, &c); err != nil { return fmt.Errorf("Malformed configuration: %s", err) } } if c.IncomingPort <= 0 || c.IncomingPort >= 65535 { c.IncomingPort = 50007 } if err := s.reconfigure(c); err != nil { return fmt.Errorf("initial configure failed: %s", err) } //poll torrents and files go func() { for { s.state.Lock() s.state.Torrents = s.engine.GetTorrents() s.state.Downloads = s.listFiles() // log.Printf("torrents #%d files #%d", len(s.state.Torrents), len(s.state.Downloads.Children)) s.state.Unlock() s.state.Update() time.Sleep(1 * time.Second) } }() host := s.Host if host == "" { host = "0.0.0.0" } addr := fmt.Sprintf("%s:%d", host, s.Port) proto := "http" if tls { proto += "s" } log.Printf("Listening at %s://%s", proto, addr) if s.Open { openhost := host if openhost == "0.0.0.0" { openhost = "localhost" } go func() { time.Sleep(1 * time.Second) open.Run(fmt.Sprintf("%s://%s:%d", proto, openhost, s.Port)) }() } h := http.Handler(http.HandlerFunc(s.handle)) if s.Log { h = requestlog.Wrap(h) } if tls { return http.ListenAndServeTLS(addr, s.CertPath, s.KeyPath, h) } else { return http.ListenAndServe(addr, h) } }