使 SimpleCookieJar 支持并发读写

This commit is contained in:
czp 2018-03-03 03:09:34 +08:00
parent 21e106030d
commit a182d56fc6
7 changed files with 274 additions and 21 deletions

View File

@ -24,13 +24,18 @@ public class ErrorResponseConverterInterceptor implements Interceptor {
JsonObject jsonObject = InterceptorHelper.getJsonInBody(response);
JsonElement code = jsonObject.get("code");
//code 字段不存在
if (code == null) {
if (code == null || code.isJsonNull()) {
return response;
}
//code 0
if (code.getAsInt() == ServerErrorCode.Common.OK) {
try {
if (code.getAsInt() == ServerErrorCode.Common.OK) {
return response;
}
} catch (NumberFormatException e) { //如果 code 不是数字的话直接返回
return response;
}
//打印 body
LOGGER.error("Get error response below: \n{}",
new GsonBuilder()

View File

@ -2,6 +2,7 @@ package com.hiczp.bilibili.api.web;
import com.hiczp.bilibili.api.BaseUrlDefinition;
import com.hiczp.bilibili.api.interceptor.AddFixedHeadersInterceptor;
import com.hiczp.bilibili.api.interceptor.ErrorResponseConverterInterceptor;
import com.hiczp.bilibili.api.web.cookie.SimpleCookieJar;
import com.hiczp.bilibili.api.web.live.LiveService;
import okhttp3.Cookie;
@ -53,7 +54,8 @@ public class BilibiliWebAPI {
.cookieJar(cookieJar)
.addInterceptor(new AddFixedHeadersInterceptor(
"User-Agent", browserProperties.getUserAgent()
));
))
.addInterceptor(new ErrorResponseConverterInterceptor());
interceptors.forEach(okHttpClientBuilder::addInterceptor);

View File

@ -4,41 +4,49 @@ import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class SimpleCookieJar implements CookieJar {
private Map<String, List<Cookie>> cookiesMap;
private final Map<String, List<Cookie>> cookiesMap;
public SimpleCookieJar() {
cookiesMap = new ConcurrentHashMap<>();
}
public SimpleCookieJar(Map<String, List<Cookie>> cookiesMap) {
this.cookiesMap = new ConcurrentHashMap<>(cookiesMap);
public SimpleCookieJar(@Nonnull Map<String, List<Cookie>> cookiesMap) {
this();
cookiesMap.forEach((domain, cookies) ->
this.cookiesMap.put(domain, new Vector<>(cookies))
);
}
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookies.forEach(cookie -> {
String domain = cookie.domain();
List<Cookie> savedCookies = cookiesMap.get(domain);
if (savedCookies == null) {
savedCookies = new ArrayList<>();
savedCookies.add(cookie);
cookiesMap.put(domain, savedCookies);
} else {
for (Cookie savedCookie : savedCookies) {
if (savedCookie.name().equals(cookie.name())) {
savedCookies.remove(savedCookie);
break;
}
List<Cookie> savedCookies;
synchronized (cookiesMap) {
savedCookies = cookiesMap.get(domain);
if (savedCookies == null) {
savedCookies = new Vector<>();
savedCookies.add(cookie);
cookiesMap.put(domain, savedCookies);
return;
}
savedCookies.add(cookie);
}
for (int i = savedCookies.size() - 1; i >= 0; i--) {
Cookie current = savedCookies.get(i);
if (current.name().equals(cookie.name())) {
savedCookies.remove(current);
}
}
savedCookies.add(cookie);
});
}
@ -47,13 +55,15 @@ public class SimpleCookieJar implements CookieJar {
return getCookiesForHost(url.host());
}
public List<Cookie> getCookiesForHost(String host) {
public List<Cookie> getCookiesForHost(@Nonnull String host) {
List<Cookie> cookieList = new ArrayList<>();
cookiesMap.forEach((domain, cookies) -> {
if (host.endsWith(domain)) {
//移除过期的 cookies
for (int i = cookies.size() - 1; i >= 0; i--) {
if (cookies.get(i).expiresAt() < System.currentTimeMillis()) {
cookies.remove(i);
Cookie current = cookies.get(i);
if (current.expiresAt() < System.currentTimeMillis()) {
cookies.remove(current);
}
}
cookieList.addAll(cookies);

View File

@ -1,6 +1,7 @@
package com.hiczp.bilibili.api.web.live;
import com.hiczp.bilibili.api.web.live.entity.SendHeartBeatResponseEntity;
import com.hiczp.bilibili.api.web.live.entity.UserInfoEntity;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
@ -15,4 +16,14 @@ public interface LiveService {
default Call<SendHeartBeatResponseEntity> sendHeartBeat() {
return sendHeartBeat(System.currentTimeMillis());
}
//获取用户信息
//成功时, code "REPONSE_OK"
//未登录时返回 500
@GET("User/getUserInfo")
Call<UserInfoEntity> getUserInfo(@Query("ts") long timestamp);
default Call<UserInfoEntity> getUserInfo() {
return getUserInfo(System.currentTimeMillis());
}
}

View File

@ -0,0 +1,191 @@
package com.hiczp.bilibili.api.web.live.entity;
import com.google.gson.annotations.SerializedName;
public class UserInfoEntity {
/**
* code : REPONSE_OK
* msg : ok
* data : {"uname":"czp3009","face":"http://i2.hdslb.com/bfs/face/4f65e79399ad5a1bf3f877851b2f819d5870b494.jpg","silver":22528,"gold":0,"achieve":135,"vip":0,"svip":0,"user_level":25,"user_next_level":26,"user_intimacy":926000,"user_next_intimacy":10000000,"user_level_rank":">50000","billCoin":699}
*/
@SerializedName("code")
private String code;
@SerializedName("msg")
private String msg;
@SerializedName("data")
private Data data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public static class Data {
/**
* uname : czp3009
* face : http://i2.hdslb.com/bfs/face/4f65e79399ad5a1bf3f877851b2f819d5870b494.jpg
* silver : 22528
* gold : 0
* achieve : 135
* vip : 0
* svip : 0
* user_level : 25
* user_next_level : 26
* user_intimacy : 926000
* user_next_intimacy : 10000000
* user_level_rank : >50000
* billCoin : 699
*/
@SerializedName("uname")
private String uname;
@SerializedName("face")
private String face;
@SerializedName("silver")
private int silver;
@SerializedName("gold")
private int gold;
@SerializedName("achieve")
private int achieve;
@SerializedName("vip")
private int vip;
@SerializedName("svip")
private int svip;
@SerializedName("user_level")
private int userLevel;
@SerializedName("user_next_level")
private int userNextLevel;
@SerializedName("user_intimacy")
private int userIntimacy;
@SerializedName("user_next_intimacy")
private int userNextIntimacy;
@SerializedName("user_level_rank")
private String userLevelRank;
@SerializedName("billCoin")
private int billCoin;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getFace() {
return face;
}
public void setFace(String face) {
this.face = face;
}
public int getSilver() {
return silver;
}
public void setSilver(int silver) {
this.silver = silver;
}
public int getGold() {
return gold;
}
public void setGold(int gold) {
this.gold = gold;
}
public int getAchieve() {
return achieve;
}
public void setAchieve(int achieve) {
this.achieve = achieve;
}
public int getVip() {
return vip;
}
public void setVip(int vip) {
this.vip = vip;
}
public int getSvip() {
return svip;
}
public void setSvip(int svip) {
this.svip = svip;
}
public int getUserLevel() {
return userLevel;
}
public void setUserLevel(int userLevel) {
this.userLevel = userLevel;
}
public int getUserNextLevel() {
return userNextLevel;
}
public void setUserNextLevel(int userNextLevel) {
this.userNextLevel = userNextLevel;
}
public int getUserIntimacy() {
return userIntimacy;
}
public void setUserIntimacy(int userIntimacy) {
this.userIntimacy = userIntimacy;
}
public int getUserNextIntimacy() {
return userNextIntimacy;
}
public void setUserNextIntimacy(int userNextIntimacy) {
this.userNextIntimacy = userNextIntimacy;
}
public String getUserLevelRank() {
return userLevelRank;
}
public void setUserLevelRank(String userLevelRank) {
this.userLevelRank = userLevelRank;
}
public int getBillCoin() {
return billCoin;
}
public void setBillCoin(int billCoin) {
this.billCoin = billCoin;
}
}
}

View File

@ -22,6 +22,7 @@ import java.nio.file.Paths;
SendBulletScreenTest.class,
SecurityHelperTest.class,
AuthenticatorTest.class,
WebAPITest.class,
LogoutTest.class
})
public class RuleSuite {

View File

@ -0,0 +1,33 @@
package com.hiczp.bilibili.api.test;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.hiczp.bilibili.api.web.BilibiliWebAPI;
import com.hiczp.bilibili.api.web.live.entity.UserInfoEntity;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class WebAPITest {
private static final Logger LOGGER = LoggerFactory.getLogger(WebAPITest.class);
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private BilibiliWebAPI bilibiliWebAPI;
public WebAPITest() {
try {
this.bilibiliWebAPI = Config.getBilibiliAPI().getBilibiliWebAPI();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void getUserInfo() throws IOException {
UserInfoEntity userInfoEntity = bilibiliWebAPI.getLiveService().getUserInfo()
.execute()
.body();
LOGGER.info("User info below: \n{}", GSON.toJson(userInfoEntity));
}
}