diff --git a/.gitignore b/.gitignore index d8f181c..e2cd304 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ /cert/ +/goweb +/vendor +/deploy/biukopweb-html/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4f3b7ad --- /dev/null +++ b/Dockerfile @@ -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"] \ No newline at end of file diff --git a/config.go b/config.go index a94fcc8..e7d0986 100644 --- a/config.go +++ b/config.go @@ -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 +} diff --git a/config.json b/config.json index abfdb80..d51864d 100644 --- a/config.json +++ b/config.json @@ -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/", diff --git a/deploy/config_production.json b/deploy/config_production.json index b612a4c..dfff480 100644 --- a/deploy/config_production.json +++ b/deploy/config_production.json @@ -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/", diff --git a/form_contactus.go b/form_contactus.go index 35d10cf..5a60880 100644 --- a/form_contactus.go +++ b/form_contactus.go @@ -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: diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4195161 --- /dev/null +++ b/go.mod @@ -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 +) diff --git a/html/assets/icons/address.png b/html/assets/icons/address.png new file mode 100644 index 0000000..d3730b2 Binary files /dev/null and b/html/assets/icons/address.png differ diff --git a/html/assets/icons/email.png b/html/assets/icons/email.png new file mode 100644 index 0000000..bd55e81 Binary files /dev/null and b/html/assets/icons/email.png differ diff --git a/html/assets/icons/facebook.png b/html/assets/icons/facebook.png new file mode 100644 index 0000000..08e9214 Binary files /dev/null and b/html/assets/icons/facebook.png differ diff --git a/html/assets/icons/instagram.png b/html/assets/icons/instagram.png new file mode 100644 index 0000000..8441a2b Binary files /dev/null and b/html/assets/icons/instagram.png differ diff --git a/html/assets/icons/link.png b/html/assets/icons/link.png new file mode 100644 index 0000000..ecfb773 Binary files /dev/null and b/html/assets/icons/link.png differ diff --git a/html/assets/icons/linkedin.png b/html/assets/icons/linkedin.png new file mode 100644 index 0000000..72d8ce8 Binary files /dev/null and b/html/assets/icons/linkedin.png differ diff --git a/html/assets/icons/phone.png b/html/assets/icons/phone.png new file mode 100644 index 0000000..205ca71 Binary files /dev/null and b/html/assets/icons/phone.png differ diff --git a/html/assets/icons/twitter.png b/html/assets/icons/twitter.png new file mode 100644 index 0000000..69d3c53 Binary files /dev/null and b/html/assets/icons/twitter.png differ diff --git a/http_handler.go b/http_handler.go index 5e24bb7..16e78a7 100644 --- a/http_handler.go +++ b/http_handler.go @@ -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 +} diff --git a/http_video.go b/http_video.go index 01a3483..dbe308e 100644 --- a/http_video.go +++ b/http_video.go @@ -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 } diff --git a/main.go b/main.go index aaa9e54..4389380 100644 --- a/main.go +++ b/main.go @@ -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) + } } } diff --git a/rsync.go b/rsync.go new file mode 100644 index 0000000..d4333f0 --- /dev/null +++ b/rsync.go @@ -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) + } +}