コード例 #1
0
ファイル: store.go プロジェクト: mdigger/mxstore
// Save сохраняет переданный в запросе файл в хранилище.
func (fs *FileStore) Save(c *rest.Context) error {
	fileInfo, err := fs.Store.Create(c.Request.Body) // сохраняем в хранилище
	if err != nil {
		return err
	}
	// файл успешно сохранен
	var url = c.Request.URL
	if !strings.HasSuffix(url.Path, "/") {
		// добавляем к URL запроса "/" в конце, чтобы корректно обработать
		// объединение относительного пути
		url.Path += "/"
	}
	// объединяем текущий URL запроса с именем сохраненного файла
	url, _ = url.Parse(fileInfo.Name)
	urlStr := url.String() // полный URL для доступа к файлу
	fileInfo.Name = urlStr
	c.SetHeader("Location", urlStr)
	log.WithFields(log.Fields{
		"url":  urlStr,
		"mime": fileInfo.Mimetype,
		"size": fileInfo.Size,
	}).Debug("file saved")
	// отдаем ответ с информацией о файле
	c.SetStatus(http.StatusCreated)
	return c.Write(fileInfo)
}
コード例 #2
0
ファイル: main.go プロジェクト: mdigger/mxstore
func main() {
	log.SetLevel(log.DebugLevel)
	log.SetFlags(0)
	// выводим информацию о версии сборки
	log.WithFields(log.Fields{
		"version": version,
		"date":    date,
		"build":   build,
		"name":    appName,
	}).Info("starting service")
	// разбираем параметры запуска приложения
	config := flag.String("config", appName+".json", "configuration `filename`")
	address := flag.String("address", host, "server address and `port`")
	flag.Parse()

	// загружаем конфигурацию сервиса
	log.WithField("file", *config).Info("loading service config")
	service, err := LoadConfig(*config)
	if err != nil {
		log.WithError(err).Error("loading config error")
		os.Exit(1)
	}

	// выводим список поддерживаемых MX-серверов
	mxnames := service.Auth.Names()
	if len(mxnames) == 0 {
		log.Error("no MX servers configured")
		os.Exit(1)
	}
	log.WithField("names", strings.Join(mxnames, ", ")).
		Info("supported MX servers")

	// выводим информацию о кеше авторизации
	log.WithField("lifeTime", mxlogin.CacheLifetime).
		Info("authorization cache")

	// удаляем устаревшие файлы раз в сутки
	cleanInterval := time.Hour * 24
	// выводим информацию о хранилище файлов
	log.WithFields(log.Fields{
		"path":          service.FileStore.Store.Path(),
		"lifeTime":      service.FileStore.Lifetime,
		"cleanInterval": cleanInterval,
	}).Info("file store")
	// запускаем процесс автоматического удаления старых файлов
	go func() {
		for {
			time.Sleep(cleanInterval)
			err = service.FileStore.Clean()
			if err != nil {
				log.WithField("service", "filestore").
					WithError(err).Debug("file store clean error")
			}
		}
	}()

	// инициализируем мультиплексор HTTP-запросов
	mux := &rest.ServeMux{
		Headers: map[string]string{
			"Server":            "MXStore/2.0",
			"X-API-Version":     "1.1",
			"X-Service-Version": version,
		},
		Logger:  log.WithField("service", "http"),
		Encoder: Encoder,
	}

	// обработчики файлов хранилища и аватарок
	mux.Handles(rest.Paths{
		"/mx/:mx-name/store": {
			// переходим на основное имя MX сервера, если используется синоним
			// возвращает пустой ответ, если имя сервера и так основное
			"GET": nil,
			// сохраняем в хранилище новый файл
			"POST": service.FileStore.Save,
		},
		// отдаем файл по запросу
		"/mx/:mx-name/store/*filename": {
			"GET": service.FileStore.Get,
		},
		"/mx/:mx-name/avatar": {
			// переходим на основное имя MX сервера, если используется синоним
			// возвращаем список идентификаторов пользователей и аватарок
			"GET": service.Avatars.List,
			// сохраняем в хранилище новый файл
			"POST": service.Avatars.Save,
		},
		// отдаем файл с аватаркой по запросу
		"/mx/:mx-name/avatar/*filename": {
			"GET": service.Avatars.Get,
		},
	},
		// для всех запросов требуется авторизация
		service.Auth.Authorize,
	)

	// добавляем обработчик отдачи документации
	mux.Handle("GET", "/",
		rest.Redirect("https://www.connector73.com/en#softphone"))
	// запускаем сервис с ответом об информации о ссылке
	mux.Handle("GET", "/urlinfo/*url", URLInfo)
	// генератор аватарок
	mux.Handle("GET", "/avatar/:id", AvatarGenerator)

	// инициализируем HTTP-сервер
	server := &http.Server{
		Addr:         *address,
		Handler:      mux,
		ReadTimeout:  time.Second * 60,
		WriteTimeout: time.Second * 120,
	}
	// для защищенного соединения проделываем дополнительные настройки
	host, port, err := net.SplitHostPort(*address)
	if err != nil {
		log.WithError(err).Error("bad server address")
		os.Exit(2)
	}

	if port == "https" || port == "443" {
		if host != "localhost" && host != "127.0.0.1" {
			manager := autocert.Manager{
				Prompt:     autocert.AcceptTOS,
				HostPolicy: autocert.HostWhitelist(host),
				Email:      "*****@*****.**",
				Cache:      autocert.DirCache("letsEncript.cache"),
			}
			server.TLSConfig = &tls.Config{
				GetCertificate: manager.GetCertificate,
			}
		} else {
			// исключительно для отладки
			cert, err := tls.X509KeyPair(LocalhostCert, LocalhostKey)
			if err != nil {
				panic(fmt.Sprintf("local certificates error: %v", err))
			}
			server.TLSConfig = &tls.Config{
				Certificates: []tls.Certificate{cert},
			}
		}
		// запускаем автоматический переход для HTTP на HTTPS
		go func() {
			log.Info("starting http to https redirect server")
			err := http.ListenAndServe(":http", http.HandlerFunc(
				func(w http.ResponseWriter, r *http.Request) {
					http.Redirect(w, r,
						"https://"+r.Host+r.URL.String(),
						http.StatusMovedPermanently)
				}))
			if err != nil {
				log.WithError(err).Warning("http redirect server error")
			}
		}()
		// запускаем основной сервер
		go func() {
			log.WithFields(log.Fields{
				"address": server.Addr,
				"host":    host,
			}).Info("starting https server")
			err = server.ListenAndServeTLS("", "")
			// // корректно закрываем сервисы по окончании работы
			// service.Close()
			log.WithError(err).Warning("https server stoped")
			os.Exit(3)
		}()
	} else {
		// не защищенный HTTP сервер
		go func() {
			log.WithField("address", *address).Info("starting service")
			err = server.ListenAndServe()
			// service.Close()
			log.WithError(err).Warning("http server stoped")
			os.Exit(3)
		}()
	}

	// инициализируем поддержку системных сигналов и ждем, когда он случится
	monitorSignals(os.Interrupt, os.Kill)
	// service.Close()
	log.Info("service stoped")
}