| @@ -1 +1,4 @@ | |||
| /cert/ | |||
| /goweb | |||
| /vendor | |||
| /deploy/biukopweb-html/ | |||
| @@ -0,0 +1,27 @@ | |||
| FROM alpine:3.16 | |||
| # make sure it support go binary library | |||
| # https://stackoverflow.com/questions/34729748/installed-go-binary-not-found-in-path-on-alpine-linux-docker | |||
| RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 | |||
| # we don't compile golang at alpine, but we will compile it at somewhere else. | |||
| ENV GO111MODULE=on | |||
| ENV GOFLAGS=-mod=vendor | |||
| #APP HOME | |||
| ENV APP_HOME /biukop/web | |||
| RUN mkdir -p "$APP_HOME" | |||
| #update static html files | |||
| RUN mkdir -p $APP_HOME/html | |||
| COPY ./deploy/biukopweb-html $APP_HOME/html | |||
| #copy production configuration file | |||
| COPY ./deploy/config_production.json $APP_HOME/config.json | |||
| COPY ./goweb $APP_HOME/goweb | |||
| WORKDIR "$APP_HOME" | |||
| EXPOSE 8080 | |||
| ENV PATH "$APP_HOME:$PATH" | |||
| CMD ["goweb", "-f", "config.json"] | |||
| @@ -4,24 +4,28 @@ import ( | |||
| "encoding/json" | |||
| "io/ioutil" | |||
| "log" | |||
| "os" | |||
| "path/filepath" | |||
| ) | |||
| type configStaticHtml struct { | |||
| Dir string | |||
| StaticUrl string | |||
| StripPrefix string | |||
| Sync string | |||
| } | |||
| type configuration struct { | |||
| Host string | |||
| Port string | |||
| DSN string | |||
| TlsCert string | |||
| TlsKey string | |||
| Static []configStaticHtml | |||
| Debug bool | |||
| TempDir string | |||
| Session struct { //TODO: figure what is this intended for | |||
| Host string | |||
| Port string | |||
| DSN string | |||
| TlsCert string | |||
| TlsKey string | |||
| RSyncKey string | |||
| Static []configStaticHtml | |||
| Debug bool | |||
| TempDir string | |||
| Session struct { //TODO: figure what is this intended for | |||
| Guest bool | |||
| Year int //how many years | |||
| Month int //how many years | |||
| @@ -41,8 +45,52 @@ func (m *configuration) readConfig() (e error) { | |||
| } | |||
| e = json.Unmarshal(body, m) | |||
| // Check upload dir and defaults | |||
| if !config.checkUploadDir() { | |||
| log.Fatal("bad config file", configFile) | |||
| return | |||
| } | |||
| if config.Debug { | |||
| log.Println(config) | |||
| } | |||
| return | |||
| } | |||
| func (m *configuration) checkUploadDir() (valid bool) { | |||
| valid = true | |||
| for idx, node := range m.Static { | |||
| if node.StaticUrl == "/" { | |||
| if !fileExists(node.Dir) { | |||
| valid = false | |||
| log.Fatal(" html / not exist ", node) | |||
| } else { | |||
| // convert to absolute path : fileDir | |||
| p, e := filepath.Abs(node.Dir) | |||
| if e != nil { | |||
| valid = false | |||
| log.Fatal("bad html (webroot) dir ", node, e) | |||
| } | |||
| m.Static[idx].Dir = p + string(os.PathSeparator) //change it to absolute dir | |||
| } | |||
| } | |||
| } | |||
| // convert rsync key file to absolute dir | |||
| p, e := filepath.Abs(config.RSyncKey) | |||
| if e != nil { | |||
| valid = false | |||
| log.Fatal("bad html (webroot) dir ", config.RSyncKey, e) | |||
| } | |||
| m.RSyncKey = p //change it to absolute dir | |||
| return | |||
| } | |||
| func fileExists(path string) bool { | |||
| if _, err := os.Stat(path); os.IsNotExist(err) { | |||
| // path/to/whatever does not exist | |||
| return false | |||
| } | |||
| return true | |||
| } | |||
| @@ -5,11 +5,13 @@ | |||
| "TlsCert": "cert/fullchain.pem", | |||
| "TlsKey": "cert/privkey.pem", | |||
| "Debug": true, | |||
| "RSyncKey": "cert/rsync.key", | |||
| "Static": [ | |||
| { | |||
| "Dir": "/mnt/hgfs/workspace/2021-07-31-BiukopWeb", | |||
| "Dir": "./deploy/biukopweb-html/", | |||
| "StaticUrl": "/", | |||
| "StripPrefix" : "/" | |||
| "StripPrefix" : "/", | |||
| "Sync": "a@c5015.biukop.com.au:/home/a/public_html/" | |||
| }, | |||
| { | |||
| "Dir": "./html/test/", | |||
| @@ -5,11 +5,13 @@ | |||
| "TlsCert": "cert/fullchain.pem", | |||
| "TlsKey": "cert/privkey.pem", | |||
| "Debug": true, | |||
| "RSyncKey": "cert/rsync.key", | |||
| "Static": [ | |||
| { | |||
| "Dir": "./html/", | |||
| "StaticUrl": "/", | |||
| "StripPrefix" : "/" | |||
| "StripPrefix" : "/", | |||
| "Sync": "a@c5015.biukop.com.au:/home/a/public_html/" | |||
| }, | |||
| { | |||
| "Dir": "./html/test/", | |||
| @@ -24,7 +24,18 @@ func formMain(w http.ResponseWriter, r *http.Request) { | |||
| func (m *formInput) contactUs() { | |||
| ret := map[string]interface{}{} | |||
| ret["success"] = true | |||
| m.r.ParseForm() | |||
| // e := m.r.ParseForm() | |||
| e := m.r.ParseMultipartForm(32 * 1024 * 1024) | |||
| if e != nil { | |||
| return | |||
| } | |||
| for key, values := range m.r.Form { // range over map | |||
| for _, value := range values { // range over []string | |||
| fmt.Println(key, value) | |||
| } | |||
| } | |||
| name := m.r.FormValue("name") | |||
| email := m.r.FormValue("email") | |||
| message := m.r.FormValue("message") | |||
| @@ -65,12 +76,12 @@ func sendContactUs(name string, email string, userInput string) { | |||
| smtpHost := "smtp.gmail.com" | |||
| smtpPort := "587" | |||
| raw := `Subject: {name} Contact form on Biukop Web | |||
| raw := `Subject: {name} [ Contact form on Biukop Web ] | |||
| Content-Type: text/plain; charset="UTF-8" | |||
| Dear Manager, | |||
| We receive a a form submission from biukop.com.au | |||
| We received a a form submission from biukop.com.au | |||
| name : {name} | |||
| email : {email} | |||
| message: | |||
| @@ -0,0 +1,9 @@ | |||
| module github.com/lawipac/biukopweb | |||
| go 1.18 | |||
| require ( | |||
| github.com/gorilla/websocket v1.5.0 // indirect | |||
| github.com/sirupsen/logrus v1.8.1 // indirect | |||
| golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect | |||
| ) | |||
| @@ -61,21 +61,29 @@ func FileServerWith404(root http.FileSystem, handler404 FSHandler404) http.Handl | |||
| // attempt to open the file via the http.FileSystem | |||
| f, err := root.Open(upath) | |||
| if err != nil { | |||
| if os.IsNotExist(err) { | |||
| // call handler | |||
| if handler404 != nil { | |||
| doDefault := handler404(w, r) | |||
| if !doDefault { | |||
| return | |||
| } | |||
| if handledBy404Handler(handler404, w, r) { | |||
| return | |||
| } | |||
| } | |||
| } | |||
| // close if successfully opened | |||
| if err == nil { | |||
| f.Close() | |||
| // if successfully opened, check if it's dir | |||
| defer func(f http.File) { | |||
| err := f.Close() | |||
| if err != nil { | |||
| return //cannot close this file | |||
| } | |||
| }(f) | |||
| //see if it's directory | |||
| info, e := f.Stat() | |||
| if e != nil || info.IsDir() { | |||
| if handledBy404Handler(handler404, w, r) { | |||
| return | |||
| } | |||
| } | |||
| // default serve | |||
| @@ -91,3 +99,14 @@ func fileSystem404(w http.ResponseWriter, r *http.Request) (doDefaultFileServe b | |||
| http.Redirect(w, r, "/404.html", http.StatusSeeOther) | |||
| return false | |||
| } | |||
| //check if h is null, if not call this as handler. | |||
| func handledBy404Handler(h FSHandler404, w http.ResponseWriter, r *http.Request) bool { | |||
| if h != nil { | |||
| doDefault := h(w, r) | |||
| if !doDefault { | |||
| return true | |||
| } | |||
| } | |||
| return false | |||
| } | |||
| @@ -12,6 +12,7 @@ const videoPrefix = "/v/" | |||
| type vimeoPlayer struct { | |||
| VideoId string | |||
| Token string | |||
| playsinline int | |||
| autoplay int | |||
| @@ -230,9 +231,24 @@ func videoVimeo(w http.ResponseWriter, r *http.Request) { | |||
| fmt.Fprintf(w, output) | |||
| } | |||
| /** | |||
| http://v.io/v/1234567/token where token might be optional | |||
| */ | |||
| func getVimeoParams(r *http.Request) (ret vimeoPlayer) { | |||
| prefix := videoPrefix + "v/" | |||
| ret.VideoId = r.URL.Path[len(prefix):] | |||
| var IdAndToken = strings.Split(r.URL.Path[len(prefix):], "/") | |||
| if len(IdAndToken) == 1 { | |||
| ret.VideoId = IdAndToken[0] | |||
| ret.Token = "" | |||
| } else if len(IdAndToken) == 2 { | |||
| ret.VideoId = IdAndToken[0] | |||
| ret.Token = IdAndToken[1] | |||
| } else { // a default video will be given | |||
| ret.VideoId = "719542916" | |||
| ret.Token = "" | |||
| } | |||
| if strings.ToLower(r.Host) == ("v.io") { | |||
| ret.Title = "您有一条视频消息" | |||
| ret.ContentDescription = "私密视频" | |||
| @@ -258,7 +274,7 @@ func getVimeoParams(r *http.Request) (ret vimeoPlayer) { | |||
| func (m *vimeoPlayer) getUrl() (ret string) { | |||
| ret = fmt.Sprintf( | |||
| "https://player.vimeo.com/video/%s?playsinline=%d&autoplay=%d&autopause=%d&loop=%d&background=%d&muted=%d", | |||
| m.VideoId, m.playsinline, m.autoplay, m.autopause, m.loop, m.background, m.muted) | |||
| "https://player.vimeo.com/video/%s?h=%s&playsinline=%d&autoplay=%d&autopause=%d&loop=%d&background=%d&muted=%d", | |||
| m.VideoId, m.Token, m.playsinline, m.autoplay, m.autopause, m.loop, m.background, m.muted) | |||
| return | |||
| } | |||
| @@ -40,5 +40,8 @@ func setupRootFileServer() { | |||
| log.Printf("setting up static %d with %+v\n", idx, node) | |||
| fs := FileServerWith404(http.Dir(node.Dir), fileSystem404) | |||
| http.Handle(node.StaticUrl, http.StripPrefix(node.StripPrefix, fs)) | |||
| if node.Sync != "" { | |||
| // go pullStaticHtml(node.Dir, node.Sync, config.RSyncKey) | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| package main | |||
| import ( | |||
| "fmt" | |||
| log "github.com/sirupsen/logrus" | |||
| "os/exec" | |||
| "time" | |||
| ) | |||
| func pullStaticHtml(local string, remote string, key string) { | |||
| ssh := fmt.Sprintf("/usr/bin/ssh -i %s ", key) | |||
| // rsync -Pav -e "ssh -i $HOME/.ssh/someKey" username@hostname:/from/dir/ /to/dir/ | |||
| for { | |||
| cmd := exec.Command("rsync", "-Pavz", "--rsh", ssh, remote, local) | |||
| // cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr") | |||
| stdoutStderr, err := cmd.CombinedOutput() | |||
| if err != nil { | |||
| log.Error(err) | |||
| break | |||
| } | |||
| log.Printf("%s\n", stdoutStderr) | |||
| time.Sleep(5 * time.Second) | |||
| } | |||
| } | |||