penguin/golifehk

@golifehk bot in Telegram

utils/cache.go

raw ยท 4200 bytes

package utils

import (
    "bytes"
    "io"
    "log"
    "os"
    "path/filepath"
    "time"
)

type CacheStreams struct {
    Local *bytes.Buffer
    Remote *bytes.Buffer
    Path string
    Query func() ( io.ReadCloser, error )
}

func ( cs *CacheStreams ) Commit() error {

    f, err := os.OpenFile( cs.Path, os.O_CREATE | os.O_WRONLY | os.O_TRUNC, 0644 )
    if err != nil {
        return err
    }

    defer f.Close()

    _, err = io.Copy( f, bytes.NewReader( cs.Remote.Bytes() ) )
    log.Printf( "Commit: %s", cs.Path )
    return err
}

func ( cs *CacheStreams ) Reload() error {

    s, err := cs.Query()
    if err != nil {
        return err
    }

    defer s.Close()

    cs.Remote = bytes.NewBuffer( []byte{} )
    _, err = io.Copy( cs.Remote, s )

    return err
}

func ( cs *CacheStreams ) NotExpired( expires time.Duration ) bool {

    cache, err := os.Stat( cs.Path )

    if err == nil {
        expired := cache.ModTime().Add( expires * 1e9 )
        return time.Now().Before( expired )
    }

    return false
}

func CacheStreamEx( path string, readStream func() ( io.ReadCloser, error ) ) ( *CacheStreams, error ) {

    cs := CacheStreams{}
    cs.Path = path
    cs.Query = readStream

    f, err := os.Open( path )
    if err == nil {
        defer f.Close()
        cs.Local = bytes.NewBuffer( []byte{} )
        _, err = io.Copy( cs.Local, f )
        if err != nil {
            return nil, err
        }
    }

    return &cs, nil
}


func CacheStream( path string, readStream func() ( io.ReadCloser, error ), expires time.Duration ) ( *bytes.Buffer, error ) {

    cache, err := os.Stat( path )

    // Check if cache exists and not expired
    if err == nil {
        expired := cache.ModTime().Add( expires * 1e9 )
        if time.Now().Before( expired ) {
            f, err := os.Open( path )
            if err == nil {
                defer f.Close()
                log.Printf( "Using cache: %s", path )
                writeBuff := bytes.NewBuffer( []byte{} )
                _, err = io.Copy( writeBuff, f )
                if err == nil {
                    return writeBuff, nil
                }
            }
        }
    }

    err = os.MkdirAll( filepath.Dir( path ), 0750 )
    if err != nil {
        return nil, err }

    writeBuff := bytes.NewBuffer( []byte{} )

    // Get the reader that return new data
    s, err := readStream()
    if err != nil {
        return nil, err
    }

    defer s.Close()

    _, err = io.Copy( writeBuff, s )
    if err != nil {
        return nil, err
    }

    f, err := os.OpenFile( path, os.O_CREATE | os.O_WRONLY | os.O_TRUNC, 0644 )
    if err != nil {
        return nil, err
    }

    defer f.Close()

    data := writeBuff.Bytes()
    _, err = io.Copy( f, bytes.NewReader( data ) )
    if err != nil {
        return nil, err
    }

    return writeBuff, nil
}

func ChangedStream( path string, readStream func() ( io.Reader, error ), dataModTime time.Time ) ( *bytes.Buffer, error ) {

    cache, err := os.Stat( path )

    // Check if cache exists and not expired
    if err == nil {
        if dataModTime.Before( cache.ModTime() ) {
            f, err := os.Open( path )
            if err == nil {
                defer f.Close()
                log.Printf( "Reading from file: %s", path )
                writeBuff := bytes.NewBuffer( []byte{} )
                _, err = io.Copy( writeBuff, f )
                if err == nil {
                    return writeBuff, nil
                }
            }
        }
    }

    err = os.MkdirAll( filepath.Dir( path ), 0750 )
    if err != nil {
        return nil, err
    }

    writeBuff := bytes.NewBuffer( []byte{} )

    // Get the reader that return new data
    s, err := readStream()
    if err != nil {
        return nil, err
    }

    _, err = io.Copy( writeBuff, s )
    if err != nil {
        return nil, err
    }

    f, err := os.OpenFile( path, os.O_CREATE | os.O_WRONLY | os.O_TRUNC, 0644 )
    if err != nil {
        return nil, err
    }

    defer f.Close()

    data := writeBuff.Bytes()
    _, err = io.Copy( f, bytes.NewReader( data ) )
    if err != nil {
        return nil, err
    }

    return writeBuff, nil
}