package main import ( "database/sql" "fmt" "log" "net/http" "net" "os" "strconv" "time" //"errors" "github.com/labstack/gommon/color" _ "github.com/lib/pq" "gopkg.in/labstack/echo.v1" mw "gopkg.in/labstack/echo.v1/middleware" ) var ( PORT = os.Getenv("PORT") DATABASE_URL = os.Getenv("DATABASE_URL") API_LOG = os.Getenv("API_LOG") FIXED_TOKEN = os.Getenv("X_Auth_Token") ) const ( version = "v1" //fixedtoken = "2eefa2912f40a6072d28ff0b571aa820" //accesslog = "api_log" //connectionString = "user=solboxcs password=thsutleodlQj dbname=cs_ccdb sslmode=disable connect_timeout=1 host=cc-gts.ktsh.co.kr port=9000" ) type JsonFloat64 float64 func (f JsonFloat64) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf("%0.2f", f)), nil } type MessageStruct struct { Id string `json:"id"` Message string `json:"message"` } type UserStruct struct { Id string `json:"id"` Name string `json:"name"` } type ServiceStruct struct { Id string `json:"id"` Service string `json:"service"` Pass string `json:"password"` Domin string `json:"domain"` } type TrafficStruct struct { Sdate string `json:"date"` In JsonFloat64 `json:"in"` In_min JsonFloat64 `json:"in_min"` In_max JsonFloat64 `json:"in_max"` In_avg JsonFloat64 `json:"in_avg,numbers"` Out JsonFloat64 `json:"out"` Out_min JsonFloat64 `json:"out_min"` Out_max JsonFloat64 `json:"out_max"` Out_avg JsonFloat64 `json:"out_avg"` } type UsageStruct struct { Sdate string `json:"date"` Quota uint64 `json:"quota"` //Quota_min uint64 `json:"quota_min"` //Quota_max uint64 `json:"quota_max"` Used JsonFloat64 `json:"used"` Used_min JsonFloat64 `json:"used_min"` Used_max JsonFloat64 `json:"used_max"` } // Response type ErrMsgOutput struct { Status string `json:"status"` Code int `json:"errorcode"` Message string `json:"error"` } type UserOutput struct { Data []UserStruct `json:"data"` } type ServiceOutput struct { Data []ServiceStruct `json:"data"` } type TrafficOutput struct { Data []TrafficStruct `json:"data"` } type UsageOutput struct { Data []UsageStruct `json:"data"` } // Handler func hello(c *echo.Context) error { //fmt.Println("token => " + c.Form("token")) s := fmt.Sprintf("Hello, World! token = %v\n", c.Form("token")) return c.String(http.StatusOK, s) } func users(c *echo.Context) error { keyword := c.Form("lkey") db, err := sql.Open("postgres", DATABASE_URL) if err != nil { //log.Fatal(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer db.Close() var rows *sql.Rows if keyword != "" { like := "%" + keyword + "%" rows, err = db.Query("SELECT c.id, ext.name FROM cs_service.cs_customer c LEFT JOIN cs_service.cs_customer_ext ext ON ext.user_seq = c.user_seq WHERE c.del_yn = 'N' AND ext.name LIKE $1 ORDER BY c.id;", like) } else { rows, err = db.Query("SELECT c.id, ext.name FROM cs_service.cs_customer c LEFT JOIN cs_service.cs_customer_ext ext ON ext.user_seq = c.user_seq WHERE c.del_yn = 'N' ORDER BY c.id;") } if err != nil { //log.Fatal(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer rows.Close() users := make([]UserStruct, 0) var uid string var name string for rows.Next() { err = rows.Scan(&uid, &name) users = append(users, UserStruct{uid, name}) } return c.JSON(http.StatusOK, UserOutput{users}) } func services(c *echo.Context) error { qid := c.Form("id") db, err := sql.Open("postgres", DATABASE_URL) if err != nil { //log.Fatal(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer db.Close() res, err := db.Query("SELECT base_domain FROM cs_service.cs_cc_info") if err != nil { //log.Fatal(err) //panic(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer res.Close() var base string for res.Next() { err = res.Scan(&base) } var rows *sql.Rows if qid != "" { rows, err = db.Query("SELECT c.id, c.passwd, s.svc_id FROM cs_service.cs_customer c, cs_service.cs_service s WHERE c.user_seq = s.user_seq AND c.id = $1 AND code NOT IN($2) AND s.status_code = $3 ORDER BY c.id", qid, "SVC_TYPE_A_02", "SVC_STATUS_ING") } else { rows, err = db.Query("SELECT c.id, c.passwd, s.svc_id FROM cs_service.cs_customer c, cs_service.cs_service s WHERE c.user_seq = s.user_seq AND code NOT IN($1) AND s.status_code = $2 ORDER BY c.id", "SVC_TYPE_A_02", "SVC_STATUS_ING") } if err != nil { //log.Fatal(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer rows.Close() services := make([]ServiceStruct, 0) var uid string var passwd string var sid string for rows.Next() { err = rows.Scan(&uid, &passwd, &sid) services = append(services, ServiceStruct{uid, sid, passwd, base}) } return c.JSON(http.StatusOK, ServiceOutput{services}) } func service(c *echo.Context) error { //return c.String(http.StatusOK, "Hello, service!!!! svc_id = %v\n", c.Param("svc_id")) in := c.Param("svc_id") db, err := sql.Open("postgres", DATABASE_URL) if err != nil { //log.Fatal(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer db.Close() res, err := db.Query("SELECT base_domain FROM cs_service.cs_cc_info") if err != nil { //log.Fatal(err) //panic(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer res.Close() var base string for res.Next() { err = res.Scan(&base) } rows, err := db.Query("SELECT c.id, c.passwd, s.svc_id FROM cs_service.cs_customer c, cs_service.cs_service s WHERE c.user_seq = s.user_seq AND s.svc_id = $1 AND code NOT IN($2) AND s.status_code = $3 ORDER BY c.id", in, "SVC_TYPE_A_02", "SVC_STATUS_ING") if err != nil { //log.Fatal(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer rows.Close() services := make([]ServiceStruct, 0) var uid string var passwd string var sid string for rows.Next() { err = rows.Scan(&uid, &passwd, &sid) services = append(services, ServiceStruct{uid, sid, passwd, base}) } return c.JSON(http.StatusOK, ServiceOutput{services}) } func traffic(c *echo.Context) error { sid := c.Param("svc_id") sdata := c.Form("start_date") edata := c.Form("end_date") now := time.Now() if sdata == "" { sdata = fmt.Sprintf("%v%v%v", now.Year(), now.Month(), now.Day()) } if edata == "" { edata = fmt.Sprintf("%v%v%v", now.Year(), now.Month(), now.Day()) } sdata += " 00:00:00" edata += " 23:59:59" db, err := sql.Open("postgres", DATABASE_URL) if err != nil { log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer db.Close() res, err := db.Query("SELECT user_seq, svc_seq FROM cs_service.cs_service WHERE svc_id = $1", sid) if err != nil { log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer res.Close() var useq uint64 var sseq uint64 //fmt.Printf("value %v => %v", sid, useq) for res.Next() { err = res.Scan(&useq, &sseq) //fmt.Printf("value 1 => %v",useq) } if useq == 0 || sseq == 0 { log.Println("Not Found Service.[", sid, "]") return echo.NewHTTPError(http.StatusNotFound) } var rows *sql.Rows qstr := `select b.all_dates reg_date, round(coalesce(up_traffic_sum, 0), 2) up_traffic_sum, round(coalesce(up_traffic_min, 0), 2) up_traffic_min, round(coalesce(up_traffic_max, 0), 2) up_traffic_max, round(coalesce(up_traffic_avg, 0), 2) up_traffic_avg, round(coalesce(down_traffic_sum, 0), 2) down_traffic_sum, round(coalesce(down_traffic_min, 0), 2) down_traffic_min, round(coalesce(down_traffic_max, 0), 2) down_traffic_max, round(coalesce(down_traffic_avg, 0), 2) down_traffic_avg from ( select distinct to_char(reg_date, 'YYYYmmdd' ) reg_date, (coalesce(max(down_traffic), 0) ) down_traffic_max, (coalesce(max(up_traffic), 0) ) up_traffic_max, (coalesce(min(down_traffic), 0) ) down_traffic_min, (coalesce(min(up_traffic), 0) ) up_traffic_min, (coalesce(sum(down_traffic), 0) ) down_traffic_sum, (coalesce(sum(up_traffic), 0) ) up_traffic_sum, (coalesce(avg(down_traffic), 0) ) down_traffic_avg, (coalesce(avg(up_traffic), 0) ) up_traffic_avg from cs_stat.cs_stat_network where 1 = 1 and svc_seq = $1 and user_seq = $2 -- AND reg_date between to_date($3::text, 'YYYY-mm-dd HH24:MI:SS') AND to_date($4::text, 'YYYY-mm-dd HH24:MI:SS') AND reg_date >= $3 AND reg_date <= $4 group by to_char(reg_date, 'YYYYmmdd') order by reg_date ) a right join (select a.all_dates from ( select distinct d1.dates as all_dates from ( select to_char(to_date($3::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYY') || month || day as dates from cs_web.cs_calen_day366 WHERE LEAP_YN = 'N' Union All select to_char(to_date($4::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYY') || month || day as dates from cs_web.cs_calen_day366 WHERE LEAP_YN = 'N' Union All SELECT to_char(to_date( to_char(to_date($3::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYY') || '0301'::text, 'YYYYmmdd') -1, 'YYYYmmdd') Union All SELECT to_char(to_date( to_char(to_date($4::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYY') || '0301'::text, 'YYYYmmdd') -1, 'YYYYmmdd') ) d1 order by d1.dates ) a where a.all_dates between (to_char(to_date($3::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYYmmdd')) and (to_char(to_date($4::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYYmmdd')) order by a.all_dates )b on a.reg_date = b.all_dates order by b.all_dates` rows, err = db.Query(qstr, sseq, useq, sdata, edata) if err != nil { log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer rows.Close() traffic := make([]TrafficStruct, 0) for rows.Next() { var v TrafficStruct err = rows.Scan(&v.Sdate, &v.In, &v.In_min, &v.In_max, &v.In_avg, &v.Out, &v.Out_min, &v.Out_max, &v.Out_avg) traffic = append(traffic, v) } return c.JSON(http.StatusOK, TrafficOutput{traffic}) } func usage(c *echo.Context) error { sid := c.Param("svc_id") sdata := c.Form("start_date") edata := c.Form("end_date") now := time.Now() if sdata == "" { sdata = fmt.Sprintf("%v%v%v", now.Year(), now.Month(), now.Day()) } if edata == "" { edata = fmt.Sprintf("%v%v%v", now.Year(), now.Month(), now.Day()) } sdata += " 00:00:00" edata += " 23:59:59" db, err := sql.Open("postgres", DATABASE_URL) if err != nil { //log.Fatal(err) log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer db.Close() res, err := db.Query("SELECT user_seq, svc_seq, stg_size FROM cs_service.cs_service WHERE svc_id = $1", sid) if err != nil { log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer res.Close() var useq uint64 var sseq uint64 var quota uint64 //fmt.Printf("value %v => %v", sid, useq) for res.Next() { err = res.Scan(&useq, &sseq, "a) //fmt.Printf("value 1 => %v",useq) } if useq == 0 || sseq == 0 { log.Println("Not Found Service.[", sid, "]") return echo.NewHTTPError(http.StatusNotFound) } var rows *sql.Rows qstr := `select b.all_dates reg_date, round(coalesce(used_stg_size_last, 0), 2) used_stg_size_last, round(coalesce(used_stg_size_max, 0), 2) used_stg_size_max, round(coalesce(used_stg_size_min, 0), 2) used_stg_size_min from ( select to_char(a.reg_date, 'YYYYmmdd' ) reg_date, (array_agg(used_stg_size ORDER BY a.reg_date DESC))[1] used_stg_size_last, max(used_stg_size) used_stg_size_max, min(used_stg_size) used_stg_size_min from cs_stat.cs_stat_storage a where svc_seq = $1 and user_seq = $2 -- AND a.reg_date between (to_date($3::text, 'YYYY-mm-dd')) AND to_date($4::text, 'YYYY-mm-dd') AND a.reg_date >= $3 AND a.reg_date <= $4 group by to_char(a.reg_date, 'YYYYmmdd') ) a right join (select a.all_dates from ( select distinct d1.dates as all_dates from ( select to_char(to_date($3::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYY') || month || day as dates from cs_web.cs_calen_day366 WHERE LEAP_YN = 'N' Union All select to_char(to_date($4::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYY') || month || day as dates from cs_web.cs_calen_day366 WHERE LEAP_YN = 'N' Union All SELECT to_char(to_date( to_char(to_date($3::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYY') || '0301'::text, 'YYYYmmdd') -1, 'YYYYmmdd') Union All SELECT to_char(to_date( to_char(to_date($4::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYY') || '0301'::text, 'YYYYmmdd') -1, 'YYYYmmdd') ) d1 order by d1.dates ) a where a.all_dates between (to_char(to_date($3::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYYmmdd')) and (to_char(to_date($4::text, 'YYYY-mm-dd HH24:MI:SS'), 'YYYYmmdd')) order by a.all_dates )b on a.reg_date = b.all_dates order by b.all_dates` rows, err = db.Query(qstr, sseq, useq, sdata, edata) if err != nil { log.Println(err) return echo.NewHTTPError(http.StatusInternalServerError) } defer rows.Close() usage := make([]UsageStruct, 0) for rows.Next() { var v UsageStruct err = rows.Scan(&v.Sdate, &v.Used, &v.Used_min, &v.Used_max) v.Quota = quota usage = append(usage, v) } /* var v UsageStruct usage := make([]UsageStruct,0); for i := 0; i < 10; i++ { v.Sdate = strconv.Itoa(i); i64 := uint64(i) v.Quota = i64 //v.Quota_min = i64 //v.Quota_max = i64 v.Used = i64 v.Used_min = i64 v.Used_max = i64 usage= append(usage,v); } */ return c.JSON(http.StatusOK, UsageOutput{usage}) } // Middleware // auth func FixedCert() echo.MiddlewareFunc { return func(h echo.HandlerFunc) echo.HandlerFunc { return func(c *echo.Context) error { //token := c.Form("token") token := c.Request().Header.Get("X-Auth-Token") if token != "" && FIXED_TOKEN == token { //fmt.Println("token => " + token) //log.Println("token => " + token) return h(c) } log.Println("ERROR : missing token.") return echo.NewHTTPError(http.StatusUnauthorized) } } } // logger(get gopkg.in/labstack/echo.v0/middleware/logger.go) func Logger() echo.MiddlewareFunc { return func(h echo.HandlerFunc) echo.HandlerFunc { return func(c *echo.Context) error { start := time.Now() if err := h(c); err != nil { c.Error(err) } end := time.Now() req := c.Request() remoteAddr := req.RemoteAddr if ip := req.Header.Get(echo.XRealIP); ip != "" { remoteAddr = ip } else if ip = req.Header.Get(echo.XForwardedFor); ip != "" { remoteAddr = ip } else { remoteAddr, _, _ = net.SplitHostPort(remoteAddr) } method := c.Request().Method path := c.Request().URL.Path if path == "" { path = "/" } size := c.Response().Size() n := c.Response().Status() code := color.Green(n) switch { case n >= 500: code = color.Red(n) case n >= 400: code = color.Yellow(n) case n >= 300: code = color.Cyan(n) } log.Printf("%s %s %s %s %s %d", remoteAddr, method, path, code, end.Sub(start), size) return nil } } } // error function func MyError(err error, c *echo.Context) { //fmt.Println("MyError" + c.Form("token")) code := http.StatusInternalServerError msg := http.StatusText(code) if he, ok := err.(*echo.HTTPError); ok { code = he.Code() msg = he.Error() } //if code == http.StatusNotFound { // c.JSON(http.StatusMethodNotAllowed, ErrMsgOutput{strconv.Itoa(code), 405, msg} ) //} else { c.JSON(code, ErrMsgOutput{strconv.Itoa(code), code, msg}) //} } func main() { // Echo instance e := echo.New() e.SetHTTPErrorHandler(MyError) // set log file f, err := os.OpenFile(API_LOG, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { //t.Fatalf("error opening file: %v", err) fmt.Printf("error opening file: %v", err) os.Exit(1) } defer f.Close() log.SetOutput(f) e.SetLogOutput(f) // Middleware e.Use(Logger()) e.Use(mw.Recover()) e.Use(FixedCert()) // Error //e.Use(func(*echo.Context) error { // return errors.New("error") //}) // Routes e.Get("/", hello) //e.Get("/user", users) //e.Get("/service", services) ver := e.Group("/" + version) //dev := e.Group("/" + "dev") // Management class gm := ver.Group("/" + "management") gm.Get("/user", users) gms := gm.Group("/" + "service") gms.Get("", services) gms.Get("/:svc_id", service) // Statistics class gs := ver.Group("/" + "statistics") //gs := dev.Group("/" + "statistics") gss := gs.Group("/" + "service") gss.Get("/:svc_id/traffic", traffic) gss.Get("/:svc_id/usage", usage) // Start server (HTTP) log.Printf("Listening on :%s", PORT) e.Run(":" + PORT) // Start server (HTTPS) //e.RunTLS(":1323", "cert.pem", "key.pem") }