diff options
author | root <sina@snix.ir> | 2022-01-13 13:47:30 +0000 |
---|---|---|
committer | root <sina@snix.ir> | 2022-01-13 13:47:30 +0000 |
commit | 4039849464722c1ddadcacd136ae7e2f59835d63 (patch) | |
tree | c1a2eff7406edef94f5805bdfae8149b08f1d0d2 /apid |
snix mirror
Diffstat (limited to 'apid')
-rwxr-xr-x | apid/api.pdf | bin | 0 -> 49211 bytes | |||
-rw-r--r-- | apid/apid.go | 251 | ||||
-rw-r--r-- | apid/const.go | 56 | ||||
-rw-r--r-- | apid/dbmid.go | 69 |
4 files changed, 376 insertions, 0 deletions
diff --git a/apid/api.pdf b/apid/api.pdf Binary files differnew file mode 100755 index 0000000..a743708 --- /dev/null +++ b/apid/api.pdf diff --git a/apid/apid.go b/apid/apid.go new file mode 100644 index 0000000..bc46f14 --- /dev/null +++ b/apid/apid.go @@ -0,0 +1,251 @@ +// Copyright 2021 SNIX LLC sina@snix.ir +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// version 2 as published by the Free Software Foundation. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +package apid + +import ( + "context" + "encoding/json" + "goshkan/ntcp" + "goshkan/opts" + "goshkan/rgdb" + "goshkan/rgxp" + "net/http" + "regexp" +) + +type ApiHandler struct { + database *rgdb.MariaSQLDB +} + +type apiMiddRegex struct { + ctx context.Context + err chan error + dch chan interface{} +} + +func newapiListRegex(c context.Context) *apiMiddRegex { + var err, dch = make(chan error), make(chan interface{}) + return &apiMiddRegex{ctx: c, err: err, dch: dch} +} + +func NewApid(sqlhandler *rgdb.MariaSQLDB) *ApiHandler { + return &ApiHandler{database: sqlhandler} +} + +func newHTTPServer(router *http.ServeMux) *http.Server { + return &http.Server{ + Addr: opts.Settings.ApiAdd, + Handler: router, + ReadTimeout: writeTime, + WriteTimeout: readxTime, + MaxHeaderBytes: maxHXSize, + } +} + +func (pr *ApiHandler) Run() { + router := http.NewServeMux() + router.HandleFunc(rootShoPDF, pr.rootHandleFX) + router.HandleFunc(urlListAll, pr.listAllRegex) + router.HandleFunc(addNewREGX, pr.addNewRegexp) + router.HandleFunc(deleteREGX, pr.deleteRegexp) + + opts.APISRV(startAPID, opts.Settings.ApiAdd) + + defer pr.database.Handler.Close() + opts.APIERR(newHTTPServer(router).ListenAndServe()) + +} + +func (pr *ApiHandler) rootHandleFX(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != rootShoPDF { + httpError(w, r, http.StatusBadRequest) + return + } + if r.Method != http.MethodGet { + httpError(w, r, http.StatusMethodNotAllowed) + return + } + w.WriteHeader(http.StatusOK) + w.Write(embedPDF) +} + +func (pr *ApiHandler) listAllRegex(w http.ResponseWriter, r *http.Request) { + opts.APIDBG(dbugNewRq, r.RemoteAddr, r.RequestURI) + if r.URL.Path != urlListAll { + httpError(w, r, http.StatusBadRequest) + return + } + + if r.Method != http.MethodGet { + httpError(w, r, http.StatusMethodNotAllowed) + return + } + + ctx, cancel := context.WithTimeout(context.Background(), dbMiddleCTX) + defer cancel() + + middle := newapiListRegex(ctx) + go middle.loadAllRegexCTX(pr.database) + + select { + case err := <-middle.err: + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + + case dba := <-middle.dch: + httpOKLog(w, r, dba.(rgdb.RegexList)) + + case <-r.Context().Done(): + opts.APIDBG(ctxIsDone, r.RemoteAddr, r.RequestURI) + } + +} + +func (pr *ApiHandler) addNewRegexp(w http.ResponseWriter, r *http.Request) { + opts.APIDBG(dbugNewRq, r.RemoteAddr, r.RequestURI) + if r.URL.Path != addNewREGX { + httpError(w, r, http.StatusBadRequest) + return + } + + if r.Method != http.MethodPost { + httpError(w, r, http.StatusMethodNotAllowed) + return + } + + r.Body = http.MaxBytesReader(w, r.Body, MaxBDSise) + var input rgdb.RegStruct + dec := json.NewDecoder(r.Body) + dec.DisallowUnknownFields() + if err := dec.Decode(&input); err != nil { + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + if len(input.Regex) < 1 { + opts.APIDBG(errRgISZero, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(errRgISZero)) + return + } + + if _, err := regexp.Compile(input.Regex); err != nil { + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + ctx, cancel := context.WithTimeout(context.Background(), dbMiddleCTX) + defer cancel() + + middle := newapiListRegex(ctx) + go middle.saveRegexToDB(pr.database, &input.Regex) + + select { + case err := <-middle.err: + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + + case <-middle.dch: + rgxp.AddRecompileReg(&input.Regex) + w.WriteHeader(http.StatusOK) + + case <-r.Context().Done(): + opts.APIDBG(ctxIsDone, r.RemoteAddr, r.RequestURI) + } +} + +func (pr *ApiHandler) deleteRegexp(w http.ResponseWriter, r *http.Request) { + opts.APIDBG(dbugNewRq, r.RemoteAddr, r.RequestURI) + if r.URL.Path != deleteREGX { + httpError(w, r, http.StatusBadRequest) + return + } + + if r.Method != http.MethodPost { + httpError(w, r, http.StatusMethodNotAllowed) + return + } + + r.Body = http.MaxBytesReader(w, r.Body, MaxBDSise) + var input rgdb.RegStruct + dec := json.NewDecoder(r.Body) + dec.DisallowUnknownFields() + if err := dec.Decode(&input); err != nil { + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(err.Error())) + return + } + + if input.RegID == 0 { + opts.APIDBG(errIdIsZero, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(errIdIsZero)) + return + } + + ctx, cancel := context.WithTimeout(context.Background(), dbMiddleCTX) + defer cancel() + + middle := newapiListRegex(ctx) + go middle.deltRegexFromDB(pr.database, input.RegID) + + select { + case err := <-middle.err: + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + + case regs := <-middle.dch: + deltRegxOK(w, r, regs.(*string)) + + case <-r.Context().Done(): + opts.APIDBG(ctxIsDone, r.RemoteAddr, r.RequestURI) + } + +} + +func deltRegxOK(w http.ResponseWriter, r *http.Request, delreg *string) { + if err := rgxp.DelRecompileReg(delreg); err != nil { + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + if err := ntcp.RemoveFromMap(delreg); err != nil { + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(err.Error())) + return + } + + w.WriteHeader(http.StatusOK) +} + +func httpError(w http.ResponseWriter, r *http.Request, code int) { + http.Error(w, http.StatusText(code), code) + opts.APIDBG(http.StatusText(code), r.RemoteAddr, r.RequestURI) +} + +func httpOKLog(w http.ResponseWriter, r *http.Request, d rgdb.RegexList) { + enc := json.NewEncoder(w) + enc.SetIndent(jsonDefault, jsonNEWPRTX) + w.WriteHeader(http.StatusOK) + if err := enc.Encode(d); err != nil { + opts.APIDBG(err, r.RemoteAddr, r.RequestURI) + } +} diff --git a/apid/const.go b/apid/const.go new file mode 100644 index 0000000..728be5a --- /dev/null +++ b/apid/const.go @@ -0,0 +1,56 @@ +// Copyright 2021 SNIX LLC sina@snix.ir +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// version 2 as published by the Free Software Foundation. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +package apid + +import ( + _ "embed" + "time" +) + +const ( + writeTime = 20 * time.Second + readxTime +) + +const ( + dbMiddleCTX = 15 * time.Second +) + +const ( + errIdIsZero = "err: RegID cannot be equal or less than zero" + errRgISZero = "err: Regex cannot be nothing or empty string" +) + +const ( + maxHXSize = 1 << 14 + MaxBDSise = 8 << 15 +) + +const ( + startAPID = "starting api service at:" + dbugNewRq = "http req:" + ctxIsDone = "ctx Done() request cancelled by user" +) + +const ( + urlListAll = "/api/all/" + addNewREGX = "/api/add/" + deleteREGX = "/api/del/" + rootShoPDF = "/" +) + +const ( + jsonDefault = "" + jsonNEWPRTX = "\x09" +) + +//go:embed api.pdf +var embedPDF []byte diff --git a/apid/dbmid.go b/apid/dbmid.go new file mode 100644 index 0000000..240263e --- /dev/null +++ b/apid/dbmid.go @@ -0,0 +1,69 @@ +// Copyright 2021 SNIX LLC sina@snix.ir +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// version 2 as published by the Free Software Foundation. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +package apid + +import ( + "goshkan/rgdb" +) + +func (pr *apiMiddRegex) errorOrCancel(err error) { + select { + case pr.err <- err: + case <-pr.ctx.Done(): + } +} + +func (pr *apiMiddRegex) sendOnChannel(data interface{}) { + select { + case pr.dch <- data: + case <-pr.ctx.Done(): + } +} + +func (pr *apiMiddRegex) loadAllRegexCTX(h *rgdb.MariaSQLDB) { + data, err := h.LoadAllRegex(pr.ctx) + if err != nil { + pr.errorOrCancel(err) + return + } + pr.sendOnChannel(data) + +} + +func (pr *apiMiddRegex) saveRegexToDB(h *rgdb.MariaSQLDB, ptrn *string) { + if err := h.RegexIFExist(pr.ctx, ptrn); err != nil { + pr.errorOrCancel(err) + return + } + + if err := h.AddNewRegex(pr.ctx, ptrn); err != nil { + pr.errorOrCancel(err) + return + } + + pr.sendOnChannel(nil) +} + +func (pr *apiMiddRegex) deltRegexFromDB(h *rgdb.MariaSQLDB, regid uint) { + regex, err := h.GetRegexByID(pr.ctx, regid) + if err != nil { + pr.errorOrCancel(err) + return + } + + if err := h.DeleteRegex(pr.ctx, regid); err != nil { + pr.errorOrCancel(err) + return + } + + pr.sendOnChannel(regex) + +} |