//
// _/_/_/ _/ _/_/_/_/_/
// _/ _/_/ _/_/ _/ _/ _/ _/_/ _/_/
// _/ _/_/ _/_/_/_/ _/_/_/_/ _/_/ _/ _/ _/ _/ _/
// _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/
// _/_/_/ _/_/_/ _/_/_/ _/ _/ _/_/_/_/_/ _/_/ _/_/
//
//
// Copyright (c) 2015-2016, Geek Zoo Studio
// http://www.geek-zoo.com
//
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
package com.BeeFramework.model;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.BeeFramework.Utils.JsonFormatTool;
import com.external.androidquery.callback.AjaxCallback;
import com.external.androidquery.callback.AjaxStatus;
import com.external.androidquery.util.AQUtility;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class BeeCallback<T> extends AjaxCallback<T>
{
public String message;
public String requset;
public String response;
public String netSize;
public long startTimestamp;
public long endTimestamp;
static Handler mHandler = null;
static Date bandwidthMeasurementDate = new Date();
public static Date throttleWakeUpTime = null;
public static long maxBandwidthPerSecond = 14800;
//上一秒所有线程传输数据大小
public static long bandwidthUsedInLastSecond = 0;
public static long averageBandwidthUsedPerSecond = 0;
static boolean forceThrottleBandwith = false;
static Object bandwidthThrottlingLock = new Object();
Timer timer;
TimerTask task;
public BeeCallback()
{
super();
startTimestamp = System.currentTimeMillis();
if(BeeQuery.environment() == BeeQuery.ENVIROMENT_DEVELOPMENT)
{
if (null == mHandler)
{
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == 1)
{
BeeCallback.this.performThrottling();
}
}
};
}
task = new TimerTask(){
public void run() {
Message message = new Message();
message.what = 1;
mHandler.sendMessage(message);
}
};
timer = new Timer(true);
if (BeeCallback.isBandwidthThrottled())
{
timer.schedule(task,250, 250);
}
}
}
@Override
public void run()
{
long interval = 0;
if(BeeQuery.environment() == BeeQuery.ENVIROMENT_DEVELOPMENT)
{
try {
synchronized (bandwidthThrottlingLock)
{
if (null != throttleWakeUpTime)
{
if (throttleWakeUpTime.after(new Date()))
{
if (!AQUtility.isUIThread())
{
Date nowDate = new Date();
interval = throttleWakeUpTime.getTime() - nowDate.getTime();
}
}
else
{
//TODO schedule callback
}
}
}
if (interval > 0)
{
Thread.sleep(interval);
}
}
catch (Exception e)
{
}
}
super.run();
}
@Override
public void callback()
{
super.callback();
int bytes = 0;
if (null != status.getData())
{
bytes = status.getData().length;
}
if(BeeQuery.environment() == BeeQuery.ENVIROMENT_DEVELOPMENT)
{
if (bytes > 0)
{
try {
synchronized (bandwidthThrottlingLock)
{
BeeCallback.incrementBandwidthUsedInLastSecond(bytes);
}
}
catch (Exception e)
{
}
}
timer.cancel();
}
}
public void callback(String url, T object, AjaxStatus status)
{
}
public void callback(String url, JSONObject jo, AjaxStatus status)
{
DebugMessageModel.finishSendingMessage(this);
endTimestamp = System.currentTimeMillis();
}
public static ArrayList<Integer> bandwidthUseageTracker = new ArrayList<Integer>();
static void recordBandwidthUsage()
{
if (bandwidthUsedInLastSecond == 0)
{
bandwidthUseageTracker.clear();
}
else
{
Date nowDate = new Date();
long interval = bandwidthMeasurementDate.getTime() - nowDate.getTime();
while ((interval < 0 || bandwidthUseageTracker.size() > 5) && bandwidthUseageTracker.size() > 0)
{
bandwidthUseageTracker.remove(0);
interval ++;
}
}
Log.d("THROTTLING", "[THROTTLING] ===Used:" + bandwidthUsedInLastSecond + " bytes of bandwidth in last measurement period===");
bandwidthUseageTracker.add(Integer.valueOf((int) bandwidthUsedInLastSecond));
bandwidthMeasurementDate = new Date();
bandwidthMeasurementDate.setTime(bandwidthMeasurementDate.getTime()+1000);
bandwidthUsedInLastSecond = 0;
long totalBytes = 0;
for (int i = 0; i< bandwidthUseageTracker.size(); i++)
{
Integer bytes = bandwidthUseageTracker.get(i);
totalBytes += bytes.longValue();
}
averageBandwidthUsedPerSecond = totalBytes/bandwidthUseageTracker.size();
}
static void measureBandwidthUsage()
{
try
{
if (BeeCallback.isBandwidthThrottled())
{
synchronized (bandwidthThrottlingLock)
{
if(null == bandwidthMeasurementDate || bandwidthMeasurementDate.before(new Date()))
{
BeeCallback.recordBandwidthUsage();
}
long bytesRemaining = maxBandwidthPerSecond - bandwidthUsedInLastSecond;
if (bytesRemaining < 0)
{
double extraSleepTime = (-bytesRemaining/(maxBandwidthPerSecond*1.0));
throttleWakeUpTime = new Date();
throttleWakeUpTime.setTime(throttleWakeUpTime.getTime() + (int)extraSleepTime*1000);
}
}
if (null != throttleWakeUpTime)
{
String throttle = "[THROTTLING] Sleeping request until after " + throttleWakeUpTime.toString();
System.out.print(throttle);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void performThrottling()
{
if (BeeCallback.isBandwidthThrottled())
{
BeeCallback.measureBandwidthUsage();
}
}
static long maxUploadReadLength()
{
long toRead = maxBandwidthPerSecond/4;
try
{
synchronized (bandwidthThrottlingLock)
{
if (maxBandwidthPerSecond > 0 && (bandwidthUsedInLastSecond + toRead > maxBandwidthPerSecond))
{
toRead = maxBandwidthPerSecond - bandwidthUsedInLastSecond;
if (toRead < 0)
{
toRead = 0;
}
}
if ( 0 == toRead || null == bandwidthMeasurementDate || bandwidthMeasurementDate.before(new Date()))
{
throttleWakeUpTime = bandwidthMeasurementDate;
}
}
}
catch (Exception e)
{
}
return toRead;
}
public static void incrementBandwidthUsedInLastSecond(long bytes)
{
try
{
synchronized (bandwidthThrottlingLock)
{
bandwidthUsedInLastSecond += bytes;
}
}
catch (Exception e)
{
}
}
public static boolean isBandwidthThrottled()
{
if (forceThrottleBandwith)
{
return true;
}
return false;
}
public static void setForceThrottleBandwidth(boolean throttle)
{
forceThrottleBandwith = throttle;
}
public static void setMaxBandwidthPerSecond(int bandWidth)
{
maxBandwidthPerSecond = bandWidth;
}
@Override
public void async(Context context) {
super.async(context);
}
@Override
public String toString()
{
String msgDesc = "";
SimpleDateFormat sdf = new SimpleDateFormat("MM月dd日HH时mm分ss秒SSS");
msgDesc += "创建时间:"+ sdf.format(new Date(startTimestamp)) +"\n\n";
if (0 != this.endTimestamp)
{
msgDesc += "结束时间:"+sdf.format(new Date(endTimestamp)) +"\n\n";
}
msgDesc += "消息:"+ this.getUrl()+"\n\n";
message = "消息:"+this.getUrl();
if (null != this.params)
{
msgDesc += "请求:"+this.params.toString()+"\n\n";
requset = "请求:\n"+JsonFormatTool.formatJson(this.params.toString(), " ");
}
else
{
msgDesc += "请求:{}\n\n";
requset = "请求:"+"{}";
}
if(null != this.result)
{
msgDesc += "响应:"+this.getResult().toString()+"\n\n";
response = "响应:\n"+"json:"+JsonFormatTool.formatJson(this.getResult().toString(), " ");
float f = this.getResult().toString().getBytes().length;
if(this.getResult().toString().getBytes().length > 1024)
{
float a = f/1024;
DecimalFormat df = new DecimalFormat("#.##");
msgDesc += "网络包大小:"+df.format(a)+"k";
netSize = "网络包大小:"+df.format(a)+"k";
}
else
{
msgDesc += "网络包大小:"+this.getResult().toString().getBytes().length+"b";
netSize = "网络包大小:"+this.getResult().toString().getBytes().length+"b";
}
msgDesc += "网络请求时间: " + (endTimestamp - startTimestamp)/1000;
}
else
{
String str = null;
try {
if (null != this.getStatus() && null != this.getStatus().getData())
{
str = new String(this.getStatus().getData(), this.getEncoding());
msgDesc += "响应:"+str+"\n\n";
response = "响应:"+str;
}
else
{
str = this.getStatus().getError();
msgDesc += "响应:"+str+"\n\n";
response = "响应:"+str;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
return msgDesc;
}
}