123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- package main
- import (
- "context"
- "crypto/md5"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "os"
- "os/signal"
- "path/filepath"
- "strconv"
- "strings"
- "time"
- "gopkg.in/yaml.v3"
- api "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/api"
- "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/dao"
- "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/health"
- "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/model"
- "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/worker"
- "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/internal/crypt"
- consulApi "github.com/hashicorp/consul/api"
- config "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/config"
- "wkla.no-ip.biz/gogs/Willie/MsgService/MessageService/logging"
- "github.com/go-chi/chi"
- "github.com/go-chi/chi/middleware"
- "github.com/go-chi/render"
- flag "github.com/spf13/pflag"
- )
- //apiVersion implementing api version for this service
- const apiVersion = "1"
- const servicename = "autorest-srv"
- var port int
- var sslport int
- var system string
- var serviceURL string
- var registryURL string
- var apikey string
- var ssl bool
- var configFile string
- var serviceConfig config.Config
- var consulAgent *consulApi.Agent
- var log logging.ServiceLogger
- func init() {
- // variables for parameter override
- ssl = false
- log.Info("init service")
- flag.IntVarP(&port, "port", "p", 0, "port of the http server.")
- flag.IntVarP(&sslport, "sslport", "t", 0, "port of the https server.")
- flag.StringVarP(&system, "systemid", "s", "", "this is the systemid of this service. Used for the apikey generation")
- flag.StringVarP(&configFile, "config", "c", config.File, "this is the path and filename to the config file")
- flag.StringVarP(&serviceURL, "serviceURL", "u", "", "service url from outside")
- flag.StringVarP(®istryURL, "registryURL", "r", "", "registry url where to connect to consul")
- }
- func cors(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Access-Control-Allow-Origin", "*")
- w.Header().Set("Access-Control-Allow-Methods", "*")
- w.Header().Set("Access-Control-Allow-Headers", "*")
- w.Header().Set("Access-Control-Allow-Credentials", "true")
- log.Infof("Should set headers")
- if r.Method == "OPTIONS" {
- log.Infof("Should return for OPTIONS")
- return
- }
- next.ServeHTTP(w, r)
- })
- }
- func routes() *chi.Mux {
- // sysApiHandler := api.NewSysAPIHandler(serviceConfig.SystemID, apikey)
- baseURL := fmt.Sprintf("/api/v%s", apiVersion)
- router := chi.NewRouter()
- router.Use(
- cors,
- render.SetContentType(render.ContentTypeJSON),
- middleware.Logger,
- middleware.Compress(5),
- middleware.Recoverer,
- //sysApiHandler.Handler,
- )
- router.Route("/", func(r chi.Router) {
- r.With(api.BasicAuth(servicename)).Mount(baseURL+"/models", api.ModelRoutes())
- r.With(api.BasicAuth(servicename)).Mount(baseURL+"/files", api.FilesRoutes())
- r.With(api.BasicAuth(servicename)).Mount(baseURL+"/users", api.UsersRoutes())
- r.With(api.BasicAuth(servicename)).Mount(baseURL+"/"+api.AdminPrefix, api.AdminRoutes())
- r.Mount("/health", health.Routes())
- })
- staticDir := serviceConfig.WebRoot
- if staticDir != "" {
- workDir, _ := os.Getwd()
- staticFiles, err := filepath.Abs(filepath.Join(workDir, staticDir))
- if err != nil {
- log.Alertf("can't serve static files: %s", err.Error())
- panic(1)
- }
- filesDir := http.Dir(staticFiles)
- FileServer(router, "/files", filesDir)
- }
- return router
- }
- // GetPublicInfoHandler getting server info
- func GetPublicInfoHandler(response http.ResponseWriter, request *http.Request) {
- log.Infof("GET: path: %s", request.URL.Path)
- jsonObject := make([]string, 0)
- jsonObject = append(jsonObject, "pub hund")
- jsonObject = append(jsonObject, "pub katze")
- jsonObject = append(jsonObject, "pub maus")
- render.JSON(response, request, jsonObject)
- }
- // GetPrivateInfoHandler getting server info
- func GetPrivateInfoHandler(response http.ResponseWriter, request *http.Request) {
- log.Infof("GET: path: %s", request.URL.Path)
- jsonObject := make([]string, 0)
- jsonObject = append(jsonObject, "prv hund")
- jsonObject = append(jsonObject, "prv katze")
- jsonObject = append(jsonObject, "prv maus")
- render.JSON(response, request, jsonObject)
- }
- func healthRoutes() *chi.Mux {
- router := chi.NewRouter()
- router.Use(
- cors,
- render.SetContentType(render.ContentTypeJSON),
- middleware.Logger,
- middleware.Compress(5),
- middleware.Recoverer,
- )
- router.Route("/", func(r chi.Router) {
- r.Mount("/health", health.Routes())
- })
- return router
- }
- func main() {
- log.Info("starting server")
- _, err := crypt.GenerateRandomBytes(20)
- if err != nil {
- log.Alertf("can't generate secure salts: %s", err.Error())
- panic(1)
- }
- flag.Parse()
- config.File = configFile
- if err := config.Load(); err != nil {
- log.Alertf("can't load config file: %s", err.Error())
- }
- serviceConfig = config.Get()
- initConfig()
- initGraylog()
- healthCheckConfig := health.CheckConfig(serviceConfig.HealthCheck)
- backgroundTasksConfig := worker.BackgroundConfig(serviceConfig.BackgroundTasks)
- defer log.Close()
- if serviceConfig.SystemID == "" {
- log.Fatal("system id not given, can't start! Please use config file or -s parameter")
- }
- gc := crypt.GenerateCertificate{
- Organization: "MCS Media Computer Spftware",
- Host: "127.0.0.1",
- ValidFor: 10 * 365 * 24 * time.Hour,
- IsCA: false,
- EcdsaCurve: "P256",
- Ed25519Key: true,
- }
- if serviceConfig.Sslport > 0 {
- ssl = true
- log.Info("ssl active")
- }
- storage := &dao.MongoDAO{}
- storage.InitDAO(config.Get().MongoDB)
- dao.SetStorage(storage)
- // initialise the identity managment system
- idm := dao.NewIDM()
- idm.InitIDM()
- dao.SetIDM(idm)
- health.InitHealthSystem(healthCheckConfig)
- worker.InitBackgroundTasks(backgroundTasksConfig)
- apikey = getApikey()
- log.Infof("systemid: %s", serviceConfig.SystemID)
- log.Infof("apikey: %s", apikey)
- log.Infof("ssl: %t", ssl)
- log.Infof("serviceURL: %s", serviceConfig.ServiceURL)
- if serviceConfig.RegistryURL != "" {
- log.Infof("registryURL: %s", serviceConfig.RegistryURL)
- }
- router := routes()
- walkFunc := func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
- log.Infof("%s %s", method, route)
- return nil
- }
- if err := chi.Walk(router, walkFunc); err != nil {
- log.Alertf("Logging err: %s", err.Error())
- }
- log.Info("Health routes")
- healthRouter := healthRoutes()
- if err := chi.Walk(healthRouter, walkFunc); err != nil {
- log.Alertf("Logging err: %s", err.Error())
- }
- initAutoRest()
- var sslsrv *http.Server
- var srv *http.Server
- if ssl {
- tlsConfig, err := gc.GenerateTLSConfig()
- if err != nil {
- log.Alertf("logging err: %s", err.Error())
- }
- sslsrv = &http.Server{
- Addr: "0.0.0.0:" + strconv.Itoa(serviceConfig.Sslport),
- WriteTimeout: time.Second * 15,
- ReadTimeout: time.Second * 15,
- IdleTimeout: time.Second * 60,
- Handler: router,
- TLSConfig: tlsConfig,
- }
- go func() {
- log.Infof("starting https server on address: %s", sslsrv.Addr)
- if err := sslsrv.ListenAndServeTLS("", ""); err != nil {
- log.Alertf("error starting server: %s", err.Error())
- }
- }()
- srv = &http.Server{
- Addr: "0.0.0.0:" + strconv.Itoa(serviceConfig.Port),
- WriteTimeout: time.Second * 15,
- ReadTimeout: time.Second * 15,
- IdleTimeout: time.Second * 60,
- Handler: healthRouter,
- }
- go func() {
- log.Infof("starting http server on address: %s", srv.Addr)
- if err := srv.ListenAndServe(); err != nil {
- log.Alertf("error starting server: %s", err.Error())
- }
- }()
- } else {
- // own http server for the healthchecks
- srv = &http.Server{
- Addr: "0.0.0.0:" + strconv.Itoa(serviceConfig.Port),
- WriteTimeout: time.Second * 15,
- ReadTimeout: time.Second * 15,
- IdleTimeout: time.Second * 60,
- Handler: router,
- }
- go func() {
- log.Infof("starting http server on address: %s", srv.Addr)
- if err := srv.ListenAndServe(); err != nil {
- log.Alertf("error starting server: %s", err.Error())
- }
- }()
- }
- if serviceConfig.RegistryURL != "" {
- initRegistry()
- }
- //go importData("E:/temp/backup/schematic/dev")
- //go generateTempData()
- osc := make(chan os.Signal, 1)
- signal.Notify(osc, os.Interrupt)
- <-osc
- log.Info("waiting for clients")
- ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
- defer cancel()
- srv.Shutdown(ctx)
- if ssl {
- sslsrv.Shutdown(ctx)
- }
- log.Info("finished")
- os.Exit(0)
- }
- func initGraylog() {
- log.GelfURL = serviceConfig.Logging.Gelfurl
- log.GelfPort = serviceConfig.Logging.Gelfport
- log.SystemID = serviceConfig.SystemID
- log.InitGelf()
- }
- func initRegistry() {
- //register to consul, if configured
- consulConfig := consulApi.DefaultConfig()
- consulURL, err := url.Parse(serviceConfig.RegistryURL)
- consulConfig.Scheme = consulURL.Scheme
- consulConfig.Address = fmt.Sprintf("%s:%s", consulURL.Hostname(), consulURL.Port())
- consulClient, err := consulApi.NewClient(consulConfig)
- if err != nil {
- log.Alertf("can't connect to consul. %v", err)
- }
- consulAgent = consulClient.Agent()
- check := new(consulApi.AgentServiceCheck)
- check.HTTP = fmt.Sprintf("%s/health/health", serviceConfig.ServiceURL)
- check.Timeout = (time.Minute * 1).String()
- check.Interval = (time.Second * 30).String()
- check.TLSSkipVerify = true
- serviceDef := &consulApi.AgentServiceRegistration{
- Name: servicename,
- Check: check,
- }
- err = consulAgent.ServiceRegister(serviceDef)
- if err != nil {
- log.Alertf("can't register to consul. %s", err)
- time.Sleep(time.Second * 60)
- }
- }
- func initConfig() {
- if port > 0 {
- serviceConfig.Port = port
- }
- if sslport > 0 {
- serviceConfig.Sslport = sslport
- }
- if system != "" {
- serviceConfig.SystemID = system
- }
- if serviceURL != "" {
- serviceConfig.ServiceURL = serviceURL
- }
- }
- func getApikey() string {
- value := fmt.Sprintf("%s_%s", servicename, serviceConfig.SystemID)
- apikey := fmt.Sprintf("%x", md5.Sum([]byte(value)))
- return strings.ToLower(apikey)
- }
- func initAutoRest() {
- backendPath := serviceConfig.BackendPath
- var files []string
- err := filepath.Walk(backendPath, func(path string, info os.FileInfo, err error) error {
- if !info.IsDir() {
- if strings.HasSuffix(info.Name(), ".yaml") {
- files = append(files, path)
- }
- }
- return nil
- })
- if err != nil {
- fmt.Println(err)
- }
- storage := dao.GetStorage()
- route := model.Route{
- Backend: "_system",
- Model: "backends",
- Apikey: getApikey(),
- SystemID: serviceConfig.SystemID,
- }
- worker.BackendStorageRoute = route
- // importing the files, if needed, to the database
- for _, value := range files {
- data, err := ioutil.ReadFile(value)
- bemodel := model.Backend{}
- bemodel.DataSources = make([]model.DataSource, 0)
- bemodel.Rules = make([]model.Rule, 0)
- err = yaml.Unmarshal(data, &bemodel)
- if err != nil {
- log.Alertf("%v", err)
- break
- }
- query := fmt.Sprintf("{\"backendname\": \"%s\"}", bemodel.Backendname)
- count, _, err := storage.QueryModel(route, query, 0, 10)
- if err != nil {
- log.Alertf("%v", err)
- break
- }
- if count == 0 {
- id, err := worker.StoreBackend(bemodel)
- if err != nil {
- log.Alertf("%v", err)
- break
- }
- log.Infof("model created : %s", id)
- }
- }
- //now, getting all backends from the database and register them
- query := ""
- count, backends, err := storage.QueryModel(route, query, 0, 10)
- if err != nil {
- log.Alertf("%v", err)
- return
- }
- if count > 0 {
- for _, dbmodel := range backends {
- jsonString, err := json.Marshal(dbmodel)
- if err != nil {
- log.Alertf("%v", err)
- break
- }
- bemodel := model.Backend{}
- bemodel.DataSources = make([]model.DataSource, 0)
- bemodel.Rules = make([]model.Rule, 0)
- err = json.Unmarshal(jsonString, &bemodel)
- if err != nil {
- log.Alertf("%v", err)
- break
- }
- err = registerBackend(bemodel)
- if err != nil {
- log.Alertf("%v", err)
- break
- }
- }
- }
- }
- func registerBackend(bemodel model.Backend) error {
- bemodel, err := worker.PrepareBackend(bemodel)
- if err != nil {
- return fmt.Errorf("validating backend %s, getting error: %v", bemodel.Backendname, err)
- }
- err = worker.ValidateBackend(bemodel)
- if err != nil {
- return fmt.Errorf("validating backend %s, getting error: %v", bemodel.Backendname, err)
- }
- err = worker.RegisterBackend(bemodel)
- if err != nil {
- return fmt.Errorf("error registering backend %s. %v", bemodel.Backendname, err)
- }
- backendName := model.BackendList.Add(bemodel)
- log.Infof("registering backend %s successfully.", backendName)
- return nil
- }
- // FileServer conveniently sets up a http.FileServer handler to serve
- // static files from a http.FileSystem.
- func FileServer(r chi.Router, path string, root http.FileSystem) {
- if strings.ContainsAny(path, "{}*") {
- panic("FileServer does not permit any URL parameters.")
- }
- if path != "/" && path[len(path)-1] != '/' {
- r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP)
- path += "/"
- }
- path += "*"
- r.Get(path, func(w http.ResponseWriter, r *http.Request) {
- rctx := chi.RouteContext(r.Context())
- pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*")
- fs := http.StripPrefix(pathPrefix, http.FileServer(root))
- fs.ServeHTTP(w, r)
- })
- }
|