signageful / client

0 stars 0 forks source link

Add Screensaver Support for Website Content Type #2

Closed juliankoehn closed 1 year ago

juliankoehn commented 1 year ago

User Story

As a user of the Digital Signage Player, I want to be able to cache the screensaver content in RAM so that it can be played smoothly and quickly.

Acceptance Criteria

Example Code

package screensaver

import (
    "crypto/md5"
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

const cacheExpiration = 72 * time.Hour

type cacheData struct {
    data       []byte
    timestamp  time.Time
    expiration time.Time
}

var cache = make(map[string]cacheData)

func cacheKey(url string) string {
    return fmt.Sprintf("%x", md5.Sum([]byte(url)))
}

func cacheScreensaver(url string) ([]byte, error) {
    key := cacheKey(url)
    cachedData, ok := cache[key]
    if ok {
        cachedData.expiration = time.Now().Add(cacheExpiration)
        cache[key] = cachedData
        return cachedData.data, nil
    }

    resp, err := http.Get(url)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    data, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    cache[key] = cacheData{
        data:       data,
        timestamp:  time.Now(),
        expiration: time.Now().Add(cacheExpiration),
    }
    return data, nil
}

func invalidateCache(url string) {
    key := cacheKey(url)
    delete(cache, key)
}

func runCacheGC() {
    for {
        time.Sleep(time.Hour)
        now := time.Now()
        for key, data := range cache {
            if now.After(data.expiration) {
                delete(cache, key)
            }
        }
    }
}

func init() {
    go runCacheGC()
}

In the above example, the cacheScreensaver function first checks if the screensaver content is already cached in the cache map. If it is, it updates the expiration time and returns the cached data. If not, it fetches the content from the given URL, caches it in the cache map, and returns the newly fetched data. The cache data's expiration time is set to the current time plus 72 hours. The cache data is stored in a map, with a key generated by hashing the URL. A function named invalidateCache is provided to allow invalidation of cache data for a given URL. The cache garbage collector function, runCacheGC, periodically runs to remove any cache data that has exceeded its expiration time.

Testing

package screensaver

func TestCacheScreensaver(t *testing.T) {
  // Test data
  url := "https://example.com/screensaver.jpg"
  cachedData := []byte("screensaver content")

  // Test cache hit scenario
  cache := make(map[string][]byte)
  cache[hash(url)] = cachedData
  data, err := cacheScreensaver(url, cache)
  if err != nil {
    t.Fatalf("Failed to get screensaver content: %v", err)
  }
  if !bytes.Equal(data, cachedData) {
    t.Fatalf("Expected cached data, but got %v", data)
  }

  // Test cache miss scenario
  cache = make(map[string][]byte)
  data, err = cacheScreensaver(url, cache)
  if err != nil {
    t.Fatalf("Failed to get screensaver content: %v", err)
  }
  if bytes.Equal(data, cachedData) {
    t.Fatalf("Expected newly fetched data, but got cached data")
  }

  // Test cache invalidation
  cache[hash(url)] = cachedData
  invalidateCache(url, cache)
  _, present := cache[hash(url)]
  if present {
    t.Fatalf("Cache for URL %s was not invalidated", url)
  }
}
juliankoehn commented 1 year ago

GOlang Backend Changes

Socket Events

The following events can be sent via sockets:

Event Handling

Cache

Caching of screensaver content in RAM is still pending and will be implemented in a subsequent iteration.

juliankoehn commented 1 year ago

Test Environment:

Player: Edge Player installed on Ubuntu Core 22 Content: Screensaver activated in the Admin Panel with website content (video)

Test Procedure:

Set up a new player with Ubuntu Core 22 and Edge Player installed. In the Admin Panel, activate the screensaver with website content (video). Play the video in full length and observe the screensaver. Interact with the mouse or keyboard and observe the screensaver behavior.

Test Results:

The video played in a loop as expected. The screensaver was reset when interacting with the mouse or keyboard.

Conclusion:

The Screensaver Support for Website Content Type has been implemented successfully and tested successfully. The screensaver behaves as expected and resets when interacting with the mouse or keyboard.