Gabriel
Gabriel

Reputation: 5734

Remove file once served?

Is there a way to remove the whole static directory from the server once its content was served for one time? (with served I mean being displayed on the browser once).

func main() {
    fs := http.FileServer(http.Dir(tempDir))
    http.Handle("/", fs)
    http.HandleFunc("/app/wo", workOrderApp)
    log.Fatal(http.ListenAndServe(":"+os.Args[1], nil))
}

func workOrderApp(w http.ResponseWriter, r *http.Request) {
    workOrderAppProcess(w)
    time.Sleep(time.Duration(4 * time.Second)) //some time to let render the html
    os.RemoveAll(tempDir)
}

The sleep os.RemoveAll was a hit and miss. Had to adjust the sleep time to a few seconds otherwise the file sometimes was served and sometimes not, I believe because bandwith or network related stuff. But it also had the side effect of delaying the whole rendering of the page.

In this example I remove all the directory, which is what I want.

func workOrderAppProcess(aid, date, language, token string, w http.ResponseWriter) {
    zipDir := os.Args[2]
    if _, err := os.Stat(tempDir); os.IsNotExist(err) {
        log.Printf("Creating directory: %v", tempDir)
        err := os.MkdirAll(tempDir, 0777)
        if err != nil {
            log.Print(err.Error())
        }
    }
    log.Printf("Extracting file: %v to: %v", date+".zip", tempDir)
    zipPath, _ := filepath.Abs(zipDir + "/" + date + ".zip")
    app.ExtractZip(zipPath, tempDir)
    batch := app.ReturnBatchNumber(tempDir + date)
    typesData := app.ReturnWorkTypeData(app.ParseXML(tempDir + date + "/" + batch + "_type_list.xml"))
    record := app.FindAppointmentRecord(aid, app.ParseXML(tempDir+date+"/"+batch+"_appt.xml"))
    signatureFileURL := app.ReturnSignatureFileURL(tempDir+date, aid, date)
    app.RenderTemplate(record, typesData, "template/wo.html", language, "/"+signatureFileURL, w)
}

Upvotes: 0

Views: 470

Answers (1)

Jonathan Hall
Jonathan Hall

Reputation: 79674

Your code is causing the HTTP handler to wait 4 seconds, delete the files, then finalize the HTTP response. Just remove the sleep.

func workOrderApp(w http.ResponseWriter, r *http.Request) {
    workOrderAppProcess(w)
    os.RemoveAll(tempDir)
}

This is more efficient, more directly reflects your intention, and doesen't leave the HTTP connection open needlessly for an extra 4 seconds.

If you have other logic in your handler not shown, and you want to ensure that the delete happens in all cases, a defer can be useful:

func workOrderApp(w http.ResponseWriter, r *http.Request) {
    workOrderAppProcess(w)
    defer os.RemoveAll(tempDir)
    /* Other logic that may do things */
}

After discussion in chat, it's apparent that workOrderAppProcess is rendering your HTML, and that os.RemoveAll is removing the images needed by that HTML. To solve this, you need to delay the removal, but after serving the HTML. This can be done with a simple goroutine:

func workOrderApp(w http.ResponseWriter, r *http.Request) {
    workOrderAppProcess(w)
    go func() {
        time.Sleep(60 * time.Second)
        os.RemoveAll(tempDir)
    }()
}

Upvotes: 3

Related Questions