// Delete item from the cache. func (fs *Fs) Delete(keys ...string) apperror.Error { for _, rawKey := range keys { key := fs.key(rawKey) if key == "" { return apperror.New("empty_key") } exists, err := utils.FileExists(fs.keyPath(key)) if err != nil { return err } if exists { if err := os.Remove(fs.keyPath(key)); err != nil { return apperror.Wrap(err, "file_delete_error") } } exists, err = utils.FileExists(fs.keyMetaPath(key)) if err != nil { return err } if exists { if err := os.Remove(fs.keyMetaPath(key)); err != nil { return apperror.Wrap(err, "file_delete_error") } } } return nil }
// Retrieve a cache item from the cache. func (fs *Fs) Get(key string, items ...kit.CacheItem) (kit.CacheItem, apperror.Error) { var item kit.CacheItem = &StrItem{} if items != nil { if len(items) != 1 { return nil, &apperror.Err{ Code: "invalid_item", Message: "You must specify one item only", } } item = items[0] } key = fs.key(key) if key == "" { return nil, apperror.New("empty_key") } exists, err := utils.FileExists(fs.keyPath(key)) if err != nil { return nil, err } if !exists { return nil, nil } metaContent, err := utils.ReadFile(fs.keyMetaPath(key)) if err != nil { return nil, err } if err := json.Unmarshal(metaContent, &item); err != nil { return nil, apperror.Wrap(err, "metadata_unmarshal_error") } // Reset ExpiresAt if it is zero, since json.Unmarshal produces // a time.Time which is not exactly equal to the zero value. if item.GetExpiresAt().IsZero() { item.SetExpiresAt(time.Time{}) } content, err := utils.ReadFile(fs.keyPath(key)) if err != nil { return nil, err } if err := item.FromString(string(content)); err != nil { return nil, apperror.Wrap(err, "cacheitem_fromstring_error") } // Return nil if item is expired. if item.IsExpired() { return nil, nil } return item, nil }
func serverRenderer(registry kit.Registry, r kit.Request) kit.Response { url := r.GetHttpRequest().URL // Build the url to query. if url.Scheme == "" { url.Scheme = "http" } if url.Host == "" { url.Host = registry.Config().UString("host", "localhost") + ":" + registry.Config().UString("port", "8000") } q := url.Query() q.Set("no-server-render", "1") url.RawQuery = q.Encode() strUrl := url.String() cacheKey := "serverrenderer_" + strUrl cacheName := registry.Config().UString("serverRenderer.cache") var cache kit.Cache // If a cache is specified, try to retrieve it. if cacheName != "" { cache = registry.Cache(cacheName) if cache == nil { registry.Logger().Errorf("serverRenderer.cache is set to %v, but the cache is not registered with app", cacheName) } } // If a cache was found, try to retrieve cached response. if cache != nil { item, err := cache.Get(cacheKey) if err != nil { registry.Logger().Errorf("serverRenderer: cache retrieval error: %v", err) } else if item != nil { // Cache item found, return response with cache item. status, _ := strconv.ParseInt(item.GetTags()[0], 10, 64) data, _ := item.ToString() return &kit.AppResponse{ HttpStatus: int(status), RawData: []byte(data), } } } // Either no cache or url not yet cached, so render it. // First, ensure that the tmp directory exists. tmpDir := path.Join(registry.Config().TmpDir(), "phantom") if ok, _ := utils.FileExists(tmpDir); !ok { if err := os.MkdirAll(tmpDir, 0777); err != nil { return &kit.AppResponse{ Error: &apperror.Err{ Code: "create_tmp_dir_failed", Message: fmt.Sprintf("Could not create the tmp directory at %v: %v", tmpDir, err), }, } } } // Build a unique file name. filePath := path.Join(tmpDir, utils.UUIdv4()+".html") // Execute phantom js. // Find path of phantom script. _, filename, _, _ := runtime.Caller(1) scriptPath := path.Join(path.Dir(path.Dir(filename)), "phantom", "render.js") start := time.Now() phantomPath := registry.Config().UString("serverRenderer.phantomJsPath", "phantomjs") args := []string{ "--web-security=false", "--local-to-remote-url-access=true", scriptPath, "10", strUrl, filePath, } result, err := exec.Command(phantomPath, args...).CombinedOutput() if err != nil { registry.Logger().Errorf("Phantomjs execution error: %v", string(result)) return &kit.AppResponse{ Error: apperror.Wrap(err, "phantom_execution_failed"), } } // Get time taken as milliseconds. timeTaken := int(time.Now().Sub(start) / time.Millisecond) registry.Logger().WithFields(log.Fields{ "action": "phantomjs_render", "milliseconds": timeTaken, }).Debugf("Rendered url %v with phantomjs", url) content, err2 := utils.ReadFile(filePath) if err2 != nil { return kit.NewErrorResponse(err2) } // Find http status code. status := 200 res := regexp.MustCompile("http_status_code\\=(\\d+)").FindStringSubmatch(string(content)) if res != nil { s, _ := strconv.ParseInt(res[1], 10, 64) status = int(s) } // Save to cache. if cache != nil { lifetime := registry.Config().UInt("serverRenderer.cacheLiftetime", 3600) err := cache.Set(&caches.StrItem{ Key: cacheKey, Value: string(content), Tags: []string{strconv.FormatInt(int64(status), 10)}, ExpiresAt: time.Now().Add(time.Duration(lifetime) * time.Second), }) if err != nil { registry.Logger().Errorf("serverRenderer: Cache persist error: %v", err) } } return &kit.AppResponse{ HttpStatus: status, RawData: content, } }