redis 缓存cookie

package com.smart.InAction;

import com.google.gson.Gson;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

public class CookieTest {

    public static void main(String[] args) throws InterruptedException {
        new CookieTest().run();
    }

    public void run() throws InterruptedException {
        Jedis conn = new Jedis("localhost");
        conn.auth("admin");
        conn.select(0);

//        testLoginCookies(conn);
//        testShopppingCartCookies(conn);
//        testCacheRows(conn);
        testCacheRequest(conn);
    }

    public void testLoginCookies(Jedis conn) throws InterruptedException {
        System.out.println("\n----- testLoginCookies -----");
        String token = UUID.randomUUID().toString();

        updateToken(conn,token,"username","itemX");
        System.out.println("We just logged-in/updated token: " + token);
        System.out.println("For user: 'username'");
        System.out.println();

        System.out.println("What username do we get when we look-up that token?");
        String r = checkToken(conn, token);
        System.out.println(r);
        System.out.println();
        assert r != null;

        System.out.println("Let's drop the maximum number of cookies to 0 to clean them out");
        System.out.println("We will start a thread to do the cleaning, while we stop it later");

        CleanSessionThread thread = new CleanSessionThread(0);
        thread.start();
        Thread.sleep(1000);
        thread.quit();
        Thread.sleep(2000);
        if(thread.isAlive()){
            throw new RuntimeException("The Clean session thread is still alive");
        }
        Long s = conn.hlen("login:");
        System.out.println("The current number of sessions still available is: " + s);
        assert s == 0;
    }

    public void testShopppingCartCookies(Jedis conn) throws InterruptedException
    {
        System.out.println("\n----- testShopppingCartCookies -----");
        String token = UUID.randomUUID().toString();

        System.out.println("We'll refresh our session...");
        updateToken(conn, token, "username", "itemX");
        System.out.println("And add an item to the shopping cart");
        addCard(conn, token, "itemY", 3);
        Map<String,String> r = conn.hgetAll("cart:" + token);
        System.out.println("Our shopping cart currently has:");
        for (Map.Entry<String,String> entry : r.entrySet()){
            System.out.println("  " + entry.getKey() + ": " + entry.getValue());
        }
        System.out.println();

        assert r.size() >= 1;

        System.out.println("Let's clean out our sessions and carts");
        CleanSessionThread thread = new CleanSessionThread(0);
        thread.start();
        Thread.sleep(1000);
        thread.quit();
        Thread.sleep(2000);
        if (thread.isAlive()){
            throw new RuntimeException("The clean sessions thread is still alive?!?");
        }

        r = conn.hgetAll("cart:" + token);
        System.out.println("Our shopping cart now contains:");
        for (Map.Entry<String,String> entry : r.entrySet()){
            System.out.println("  " + entry.getKey() + ": " + entry.getValue());
        }
        assert r.size() == 0;
    }

    public void testCacheRows(Jedis conn) throws InterruptedException
    {
        System.out.println("\n----- testCacheRows -----");
        System.out.println("First, let's schedule caching of itemX every 5 seconds");
        scheduleRowCache(conn, "itemX", 5);
        System.out.println("Our schedule looks like:");
        Set<Tuple> s = conn.zrangeWithScores("schedule:", 0, -1);
        for (Tuple tuple : s){
            System.out.println("  " + tuple.getElement() + ", " + tuple.getScore());
        }
        assert s.size() != 0;

        System.out.println("We'll start a caching thread that will cache the data...");

        CacheRowsThread thread = new CacheRowsThread();
        thread.start();

        Thread.sleep(1000);
        System.out.println("Our cached data looks like:");
        String r = conn.get("inv:itemX");
        System.out.println(r);
        assert r != null;
        System.out.println();

        System.out.println("We'll check again in 5 seconds...");
        Thread.sleep(5000);
        System.out.println("Notice that the data has changed...");
        String r2 = conn.get("inv:itemX");
        System.out.println(r2);
        System.out.println();
        assert r2 != null;
        assert !r.equals(r2);

        System.out.println("Let's force un-caching");
        scheduleRowCache(conn, "itemX", -1);
        Thread.sleep(1000);
        r = conn.get("inv:itemX");
        System.out.println("The cache was cleared? " + (r == null));
        assert r == null;

        thread.quit();
        Thread.sleep(2000);
        if (thread.isAlive()){
            throw new RuntimeException("The database caching thread is still alive?!?");
        }
    }

    public void testCacheRequest(Jedis conn) {
        System.out.println("\n----- testCacheRequest -----");
        String token = UUID.randomUUID().toString();

        Callback callback = new Callback(){
            public String call(String request){
                return "content for " + request;
            }
        };

        updateToken(conn, token, "username", "itemX");
        String url = "http://test.com/?item=itemX";
        System.out.println("We are going to cache a simple request against " + url);
        String result = cacheRequest(conn, url, callback);
        System.out.println("We got initial content:\n" + result);
        System.out.println();

        assert result != null;

        System.out.println("To test that we've cached the request, we'll pass a bad callback");
        String result2 = cacheRequest(conn, url, null);
        System.out.println("We ended up getting the same response!\n" + result2);

        assert result.equals(result2);

        assert !canCache(conn, "http://test.com/");
        assert !canCache(conn, "http://test.com/?item=itemX&_=1234536");
    }

    /**
     * 检查token
     */
    public String checkToken(Jedis conn, String token){
        return conn.hget("login:",token);
    }

    /**
     * 更新token
     */
    public void updateToken(Jedis conn,String token,String user,String item){
        long timestamp = System.currentTimeMillis() / 1000;
        conn.hset("login:",token,user);
        conn.zadd("recent:",timestamp,token);
        if(item!=null){
            conn.zadd("viewed:"+token,timestamp,item);
            conn.zremrangeByRank("viewed:"+token,0,-26);
            conn.zincrby("viewed:",-1,item);
        }
    }

    /**
     * 购物车放入缓存
     */
    public void addCard(Jedis conn,String session,String item,int count){
        if(count<=0){
            conn.hdel("cart:"+session,item);
        }else{
            conn.hset("cart:"+session,item,String.valueOf(count));
        }
    }

    /**
     *缓存请求页面
     */
    public String cacheRequest(Jedis conn,String request,Callback callback){
        if(!canCache(conn,request)){
            return callback !=null ? callback.call(request) : null;
        }
        String pageKey="cache:"+hashRequest(request);
        String content = conn.get(pageKey);
        if(content ==null && callback !=null){
            content=callback.call(request);
            conn.setex(pageKey,300,content);
        }

        return content;
    }

    public boolean canCache(Jedis conn,String request){
        try {
            URL url = new URL(request);
            HashMap<String, String> params = new HashMap<String, String>();
            if(url.getQuery()!=null){
                for(String param : url.getQuery().split("&")){
                    String[] pair = param.split("=", 2);
                    params.put(pair[0],pair.length==2?pair[1]:null);
                }
            }

            String itemId = extractItemId(params);
            if(itemId==null || isDynamic(params)){
                return false;
            }

            Long rank = conn.zrank("viewed:", itemId);
            return rank!=null && rank<10000;
        } catch (MalformedURLException e) {
            return false;
        }
    }

    public String extractItemId(Map<String,String> params){
        return params.get("item");
    }

    public boolean isDynamic(Map<String,String> params){
        return params.containsKey("_");
    }

    public String hashRequest(String request){
        return String.valueOf(request.hashCode());
    }

    public void scheduleRowCache(Jedis conn,String rowId,int delay){
        conn.zadd("delay:",delay,rowId);
        conn.zadd("schedule:",System.currentTimeMillis()/1000,rowId);
    }
}

/***
 * session清除器
 */
class CleanSessionThread extends Thread{
    private Jedis conn;
    private int limit;
    private boolean quit;

    public CleanSessionThread(int limit){
        conn=new Jedis("localhost");
        conn.auth("admin");
        this.limit=limit;
    }

    public void quit(){
        quit=true;
    }

    public void run(){
        while(!quit){
            Long size = conn.zcard("recent:");
            if(size<=limit){
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                continue;
            }

            long endIndex = Math.min(size - limit, 100);
            Set<String> tokenSet = conn.zrange("recent:", 0, endIndex - 1);
            String[] tokens = tokenSet.toArray(new String[tokenSet.size()]);

            List<String> sessionTokens =new ArrayList<String>();
            for(String token : tokens){
                sessionTokens.add("viewed:"+token);
                sessionTokens.add("cart:"+token);
            }

            conn.del(sessionTokens.toArray(new String[sessionTokens.size()]));
            conn.hdel("login:",tokens);
            conn.zrem("recent:",tokens);
        }
    }
}

interface Callback{
    String call(String request);
}

class CacheRowsThread extends Thread{
    private Jedis conn;
    private boolean quit;

    public CacheRowsThread(){
        conn=new Jedis("localhost");
        conn.auth("admin");
        conn.select(0);
    }

    public void quit(){
        quit=true;
    }

    public void run(){
        Gson gson = new Gson();
        while(!quit){
            Set<Tuple> range = conn.zrangeWithScores("schedule:", 0, 0);
            Tuple next=range.size()>0 ? range.iterator().next() : null;
            long now=System.currentTimeMillis()/1000;
            if(next ==null || next.getScore() > now){
                try{
                    sleep(50);
                }catch (InterruptedException e){
                    Thread.currentThread().interrupt();
                }
                continue;
            }

            String rowId = next.getElement();
            double delay = conn.zscore("delay:", rowId);
            if(delay<=0){
                conn.zrem("delay:",rowId);
                conn.zrem("schedule:",rowId);
                conn.del("inv:"+rowId);
                continue;
            }

            Inventory row = Inventory.get(rowId);
            conn.zadd("schedule:",now+delay,rowId);
            conn.set("inv:"+rowId, gson.toJson(row));
        }
    }

    public static class Inventory {
        private String id;
        private String data;
        private long time;

        private Inventory (String id) {
            this.id = id;
            this.data = "data to cache...";
            this.time = System.currentTimeMillis() / 1000;
        }

        public static Inventory get(String id) {
            return new Inventory(id);
        }
    }
}

 

posted on 2019-03-31 21:58  溪水静幽  阅读(644)  评论(0)    收藏  举报