package com.brframework.commoncache.core;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.util.IOUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import org.redisson.client.codec.BaseCodec;
import org.redisson.client.handler.State;
import org.redisson.client.protocol.Decoder;
import org.redisson.client.protocol.Encoder;
import org.springframework.data.redis.serializer.SerializationException;

import java.io.IOException;

/**
 * Fast JSON Codec
 * 参考
 * @see com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer
 * @see org.redisson.codec.JsonJacksonCodec
 * @author xu
 * @date 2019/9/5 12:39
 */
public class FastJsonRedisCodec extends BaseCodec {
    private final static ParserConfig defaultRedisConfig = new ParserConfig();
    static { defaultRedisConfig.setAutoTypeSupport(true);}

    @Override
    public Decoder<Object> getValueDecoder() {
        return new Decoder<Object>() {
            @Override
            public Object decode(ByteBuf buf, State state) throws IOException {
                try {
                    return JSON.parseObject(new ByteBufInputStream(buf), IOUtils.UTF8, Object.class, defaultRedisConfig);
                } catch (Exception ex) {
                    throw new SerializationException("Could not deserialize: " + ex.getMessage(), ex);
                }
            }
        };
    }

    @Override
    public Encoder getValueEncoder() {
        return new Encoder() {
            @Override
            public ByteBuf encode(Object in) throws IOException {
                ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
                try {
                    ByteBufOutputStream os = new ByteBufOutputStream(out);
                    os.write(JSON.toJSONBytes(in, SerializerFeature.WriteClassName));
                    return os.buffer();
                } catch (Exception e) {
                    out.release();
                    throw new SerializationException("Could not serialize: " + e.getMessage(), e);
                }
            }
        };
    }
}
