init-a_router-func.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. package routers
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io/ioutil"
  8. "os"
  9. "runtime"
  10. "strconv"
  11. "strings"
  12. controllers_func "syncscan-go/controllers/func"
  13. "syncscan-go/cronjobs"
  14. "syncscan-go/locals"
  15. models_table "syncscan-go/models/table"
  16. "github.com/dabory/abango-rest"
  17. e "github.com/dabory/abango-rest/etc"
  18. "github.com/labstack/echo"
  19. "github.com/labstack/echo/middleware"
  20. "gopkg.in/robfig/cron.v2"
  21. )
  22. type Route struct {
  23. Method []string
  24. Path string
  25. Handler echo.HandlerFunc
  26. }
  27. var routes []Route
  28. func AddRoute(route Route) {
  29. routes = append(routes, route)
  30. }
  31. func RestRouterInit(ask *abango.AbangoAsk) {
  32. //main.go 에서는 XConfig 값을 받아 올수 없으므로 여기서 모든걸 세팅한다.
  33. if abango.XConfig["IsCronJob"] == "Yes" {
  34. err := locals.GSync.Init()
  35. if err != nil {
  36. fmt.Println("SyncDB Connection Failure is a FATAL Error. API Exit !!")
  37. os.Exit(0)
  38. }
  39. runtime.GOMAXPROCS(runtime.NumCPU()) //CPU Core 전체를 사용함.
  40. sched := cron.New()
  41. sched.AddFunc(abango.XConfig["CronJobInterval"], cronjobs.MainJob)
  42. // read manaul : https://pkg.go.dev/gopkg.in/robfig/cron.v2
  43. sched.Start()
  44. }
  45. c := echo.New()
  46. // c.Pre(middleware.BodyDump(func(c echo.Context, reqBody, resBody []byte) {
  47. c.Use(middleware.CORSWithConfig(middleware.CORSConfig{
  48. AllowOrigins: []string{"*"},
  49. // AllowOrigins: []string{"http://single.daboryhost.com", "http://fit-vac.com",
  50. AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},
  51. }))
  52. c.Pre(func(next echo.HandlerFunc) echo.HandlerFunc {
  53. return func(c echo.Context) error {
  54. r := c.Request()
  55. uri := r.URL.Path
  56. // var IsUpdateFieldListOn bool
  57. // actPostfix := uri[len(uri)-4:]
  58. // if actPostfix == "-ins" || actPostfix == "-upt" || actPostfix == "-del" { //update이외의 경우 속도증가
  59. // uri = uri[0:len(uri)-4] + "-act" // 이렇게 하면 -ins,-upt,-del 의 경우는 abg.UpdateFieldList 만드는 과정 스킵가능함.
  60. // } else if actPostfix == "-act" {
  61. // IsUpdateFieldListOn = true
  62. // }
  63. var l models_table.DbtLogAccess //변수재사용을 위하여, 실제 로그 기록은 소스 맨 아래에서 AddaRow함.
  64. l.CreatedOn = e.GetNowUnix()
  65. l.FrontIp = c.RealIP()
  66. l.Url = uri
  67. l.FrontHost = r.Header.Get("FrontendHost")
  68. l.RemoteIp = r.Header.Get("RemoteIp")
  69. l.Referer = r.Header.Get("Referer")
  70. e.OkLog(".")
  71. e.OkLog("Start >> " + l.Url + " FROM (" + l.FrontIp + ") " + l.FrontHost + " <- " + l.RemoteIp)
  72. bodyBytes, err := ioutil.ReadAll(r.Body)
  73. if err == nil { // Remove when production completes
  74. e.OkLog("Requested Json: " + string(bodyBytes))
  75. r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) // This leads ReadCloser rewinded
  76. }
  77. // 미들웨어에서 receiver 받은 것을 echo.Context 로 넘겨줌.
  78. var abg abango.Controller
  79. // var err error
  80. if uri != "/gate-token-get" { // 미리 GateToken이 있는지 확인함.
  81. abg.GateToken = r.Header.Get("GateToken")
  82. if status, msg := abg.Init(); status != 200 {
  83. return c.String(status, msg)
  84. }
  85. if err := CheckAppPerm(&abg, uri); err != nil { //SsoSubId로 들어온 App 계정체크
  86. return c.String(508, "App Permission Denied: "+err.Error())
  87. }
  88. }
  89. if uri == "/gate-token-get" { // gate-token-test 는 아웃풋없는 test 이므로 여기 없음.
  90. var v controllers_func.GateTokenGetReq
  91. err = json.NewDecoder(r.Body).Decode(&v)
  92. c.Set("receiver", v)
  93. } else if uri == "/gate-token-test" {
  94. var v controllers_func.GateTokenTestReq
  95. err = json.NewDecoder(r.Body).Decode(&v)
  96. c.Set("receiver", v)
  97. } else { //!!주의 긴 string이 먼저나오게 지정할 것
  98. if locals.HasPickActPage(uri, "dummydummy") {
  99. } else {
  100. return c.String(709, e.LogStr("ewgvdafewwa", "Request Function Not Found in Middleware for "+uri))
  101. }
  102. }
  103. if err != nil { // error 처리를 반복하지 않고 하나로 처리
  104. return c.String(800, e.JsonFormatErr("wevzxdfarfawe", uri)+" "+err.Error())
  105. }
  106. if uri[len(uri)-4:] == "-act" {
  107. var mapped map[string]interface{}
  108. // id 번호 구함.
  109. inxId := bytes.Index(bodyBytes, []byte("\"Id\""))
  110. inxIdStart := 1 + inxId + bytes.Index(bodyBytes[inxId:], []byte(":"))
  111. inxIdEnd := inxIdStart + bytes.Index(bodyBytes[inxIdStart:], []byte(","))
  112. if inxIdStart > inxIdEnd { //Delete 는 { "Id": -152 } 형태이므로 , 가 없다.
  113. inxIdEnd = inxIdStart + bytes.Index(bodyBytes[inxIdStart:], []byte("}"))
  114. }
  115. // fmt.Println("inxIdStart2:", inxIdStart)
  116. // fmt.Println("inxIdEnd2", inxIdEnd)
  117. idChar := string(bodyBytes[inxIdStart:inxIdEnd])
  118. if idChar[len(idChar)-1:] == "}" { //{"Id": -1541}, 다중 레코드의 경우도 처리
  119. idChar = idChar[:len(idChar)-1]
  120. }
  121. strId := strings.TrimSpace(idChar)
  122. intId, err := strconv.Atoi(strId)
  123. // fmt.Println("strId=", strId)
  124. if err != nil { // Id 가 정수가 아니면 치명적에러 이다. // ** 입력,수정,삭제를 복합적으로 한번에 request하는 것은 처리 안됨.
  125. return c.String(800, e.JsonFormatErr("0qjhoysaee", "Id value is not a integer "+err.Error()))
  126. }
  127. if intId > 0 { //id > 0 경우는 update인 경우만 처리한다.
  128. inxPage := bytes.Index(bodyBytes, []byte("\"Page\""))
  129. inxCoreStart := inxPage + bytes.Index(bodyBytes[inxPage:], []byte("{"))
  130. //Json 필드를 찾기 Skip 하기 위한 부분인데 만약 Json Field가 2개이상이면 For문으로 업그레이드 필요.
  131. // 현재는 setup-act 와 eyetest-act의 경우를 처리함.
  132. inxCoreJson := bytes.Index(bodyBytes, []byte("}\"")) //Json필드의 마지막은 이렇게 저장된다.
  133. inxCoreEnd := 0
  134. if inxCoreJson <= inxCoreStart { //Json 필드 없는 경우
  135. inxCoreEnd = 1 + bytes.Index(bodyBytes, []byte("}"))
  136. } else { //Json 필드 있는 경우
  137. inxCoreJson = 1 + inxCoreJson
  138. inxCoreEnd = 1 + inxCoreJson + bytes.Index(bodyBytes[inxCoreJson:], []byte("}"))
  139. }
  140. // fmt.Println("core:", string(bodyBytes[inxCoreStart:inxCoreEnd]))
  141. if err := json.Unmarshal(bodyBytes[inxCoreStart:inxCoreEnd], &mapped); err != nil {
  142. return c.String(800, e.JsonFormatErr("903uous09ur", uri))
  143. }
  144. update := ""
  145. for fld := range mapped {
  146. update += e.SnakeString(fld) + ","
  147. }
  148. abg.UpdateFieldList = update[0 : len(update)-1] //마지막 , 하니떼고
  149. // fmt.Println("UpdateFieldList:", abg.UpdateFieldList)
  150. }
  151. }
  152. // }
  153. c.Set("abango", abg) // 미들웨어에서 y.Db를 접속한 후 echo.Context 로 넘겨줌.
  154. //Log 기록 _setup반영요
  155. // if abg.GateToken != "" { //GateToken 이 있는 경우,유효 Request만 로그를 TargetDB에 쓸수가 있슴
  156. // l.MemberId = abg.Gtb.MemberId
  157. // l.UserId = abg.Gtb.UserId
  158. // if err := l.AddaRow(&abg); err != nil {
  159. // return c.String(603, err.Error())
  160. // }
  161. // }
  162. err1 := next(c)
  163. // fmt.Println("Pre 2번 미들웨어 종료")
  164. return err1
  165. }
  166. })
  167. c.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
  168. Format: "Finish >> method=${method}, uri=${uri}, status=${status} \n",
  169. }))
  170. for _, r := range routes {
  171. c.Match(r.Method, r.Path, r.Handler)
  172. }
  173. // c.Static("/.well-known/acme-challenge", "/home/.well-known/acme-challenge")
  174. xc := abango.XConfig
  175. if xc["SslMode"] == "Yes" {
  176. e.OkLog("SSL(HTTPS) Mode Started !!")
  177. //API Server 포트가 443: "https://api.dabory.com", 40443 포트: "https://api.dabory.com"
  178. c.Logger.Fatal(c.StartTLS(xc["SslConnect"], xc["SslFullChain"], xc["SslPrivate"]))
  179. } else {
  180. e.OkLog("PLAIN(HTTP) Mode Started !!")
  181. c.Logger.Fatal(c.Start(abango.XConfig["RestConnect"]))
  182. }
  183. }
  184. func CheckAppPerm(y *abango.Controller, uri string) error {
  185. if y.Gtb.SsoSubId == 0 {
  186. return nil
  187. }
  188. var qName string //이쿼리 queries 필드에거 가져와서 진행할 수 있도록 할 것.
  189. sql := `select
  190. mx.id
  191. from
  192. pro_member_app as mx
  193. inner join pro_app_perm as prm on mx.app_perm_id = prm.id
  194. inner join pro_app_perm_bd as bdy on prm.id = bdy.app_perm_id
  195. inner join pro_app_api as api on api.id = bdy.app_api_id
  196. where
  197. mx.sso_sub_id = ? and api.api_uri = ?`
  198. // qName = "kkk"
  199. //나중에 "QueryName 찾는 로직도 넣을 것
  200. if qName != "" {
  201. sql += " and api.query_name = '" + qName + "'"
  202. }
  203. // fmt.Println("y.Gtb.SsoSubId,", y.Gtb.SsoSubId)
  204. // fmt.Println("uri: ", uri)
  205. // fmt.Println("sql: ", sql)
  206. arr, err := y.Db.Query(sql, y.Gtb.SsoSubId, uri)
  207. if err != nil {
  208. return e.LogErr("3f0oijhbfre", "Query issue. ", err)
  209. }
  210. if len(arr) == 1 {
  211. return nil
  212. } else {
  213. return e.LogErr("34445ef34r", "App Api Record Issue ", errors.New(""))
  214. }
  215. }