白板点阵数据传输测试初探

2022年01月15日 阅读数:4
这篇文章主要向大家介绍白板点阵数据传输测试初探,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

近期公司上线了一个功能,就是在虚拟教室中添加了一个白板的展现框,此白板能够由老师经过配套的笔(硬件)进行绘制图形,有一些简单的功能,学生能够同步白板信息,也能够在老师受权的状况下进行绘制。java

答题需求就是这些,技术上的细节整理以下:dom

白板传输接口文档

这个文档是本人本身整理的,主要讲清楚白板数据传输接口的测试脚本实现过程遇到的问题。ide

接口逻辑


  • 用户登陆,获取token
  • 使用用户token和我的信息链接Socket
  • 使用token和我的信息注册链接
  • 加入某个房间(roomId)
  • 发送Socket消息(白板消息,后面介绍)

数据来源

白板原始数据为点坐标,经过SDK(自研)进行数据的处理,获得二进制数据,再经过base64码成字符串。长度约为几十。测试

业务处理

共有三种不一样的请求消息结构,分别为this


  • 落笔
  • 移动
  • 起笔

每次发送数据量为5个坐标点,发送数据中有UUID格式的笔画ID,用户ID(字符格式)。在落笔消息中须要添加颜色数据(10进制数字,来源为RGB颜色成10进制便可)编码


起笔和落笔可不足5个坐标点。spa


坐标分布

pad正常放置桌面(横向),白板左上角为原点(0,0),右下方坐标为(1200,760),所有在第一象限。3d

测试方案

首先我用了一个​​point​​的类用于报错某一个点的坐标信息,颜色信息在起笔过程当中传输。code

package com.okayqa.board.base;

public class Point {

public short x; // 将此值除以 10 才是点的 x 坐标

public short y; // 将此值除以 10 才是点的 x 坐标

public short width; // 将此值除以 100 才是点的宽度

private Point(int x, int y, int width) {
this.x = (short) (x * 10);
this.y = (short) (y * 10);
this.width = (short) (width * 100);
}

private Point(int x, int y) {
this(x, y, 3);
}

public static Point getPoint(int x, int y) {
if (x < 0 || x > 1199 || y < 0 || y > 760) return new Point(1, 1);
return new Point(x, y);
}

public static Point getPoint(int x, int y, int width) {
if (x < 0 || x > 1199 || y < 0 || y > 760) return new Point(1, 1, width);
return new Point(x, y, width);
}


/**
* 偏移方法
*
* @param offsetX 实际坐标点偏移量 x
* @param offsetY 实际坐标点偏移量 y
* @return
*/
public Point move(int offsetX, int offsetY) {
return getPoint(this.x / 10 + offsetX * 10, this.y / 10 + offsetY * 10);
}

@Override
public String toString() {
return "Point{ " + x + ", " + y + '}';
}


}

复制代码

而后用了一个​​BoardBase​​类封装了一些基础方法,主要是生成一些​​BoardUser​​中使用的静态方法,获取​​UUID​​和设定的几种图形的点集合。继承


​MessageHandler​​类是​​SDK​​自带的,这里继承一下只是为了方便调用其方法。


package com.okayqa.board.base;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static com.okayqa.board.base.Point.getPoint;

/**
* 白板测试:wiki:http://rap2.ailearn.ink/repository/editor?id=30&mod=69&itf=187
*/
public class BoardBase extends MessageHandler {

private static Logger logger = LoggerFactory.getLogger(BoardBase.class);

public static List<Point> getFive(int x, int y) {
if (x < 0 || x > 1199 || y < 0 || y > 760) return getFive(0, 0);
List<Point> ps = new ArrayList<>();
ps.add(getPoint(x, y));
ps.add(getPoint(x + 1, y));
ps.add(getPoint(x + 1, y + 1));
ps.add(getPoint(x + 2, y + 1));
ps.add(getPoint(x + 2, y + 2));
return ps;
}


/**
* 获取一个UUID的strokeID
*
* @return
*/
public static String getStrokeId() {
String s = DEFAULT_STRING + UUID.randomUUID().toString();
logger.info("生成了笔画ID: {}", s);
return s;
}

/**
* 获取随机颜色值
*
* @return
*/
public static int getColor() {
return getRandomInt(16777215);
}

/**
* 画一个方形
*
* @param xx 中心点x坐标
* @param yy 中心点y坐标
* @param x 横长度/2
* @param y 竖长度/2
* @return
*/
public static List<Point> square(int xx, int yy, int x, int y) {
List<Point> ps = new ArrayList<>();
Point lefttop = getPoint(xx - x, yy - y);
Point righttop = getPoint(xx + x, yy - y);
Point leftbottom = getPoint(xx - x, yy + y);
Point rightbottom = getPoint(xx + x, yy + y);
ps.addAll(line(lefttop, righttop));
ps.addAll(line(righttop, rightbottom));
ps.addAll(line(rightbottom, leftbottom));
ps.addAll(line(leftbottom, lefttop));
return ps;
}

/**
* 画直线
*
* @param start 起点
* @param end 终点
* @return
*/
public static List<Point> line(Point start, Point end) {
List<Point> ps = new ArrayList<>();
int xlength = end.x - start.x;
int ylength = end.y - start.y;
ps.add(start);
for (int i = 1; i < xlength; i++) {
int xx = start.x + i;
int yy = start.y + (ylength / xlength) * i;
ps.add(getPoint(xx, yy));
}
ps.add(end);
return ps;
}

/**
* 画圆形
*
* @param x 圆心坐标x
* @param y 圆心坐标y
* @param r 半径
* @return
*/
public static List<Point> circle(int x, int y, int r) {
List<Point> ps = new ArrayList<>();
double diff = Math.PI / 60;
for (int i = 0; i < 121; i++) {
double xx = r * (Math.cos(i * diff)) + x;
double yy = r * (Math.sin(i * diff)) + y;
ps.add(getPoint((int) xx, (int) yy));
}
return ps;
}

/**
* 画心形图案的方法
*
* @param x 圆心坐标x
* @param y 圆心坐标y
* @param r 半径
* @return
*/
public static List<Point> heart(int x, int y, int r) {
//画心形的方法
List<Point> heart = new ArrayList<>();
double d = Math.PI / 60;
for (int i = 0; i < 121; i++) {
double xx = r * (2 * Math.cos(i * d) - Math.cos(2 * i * d));
double yy = r * (2 * Math.sin(i * d) - Math.sin(2 * i * d));
heart.add(getPoint((int) yy + x, (int) xx + y));
}
return heart;
}


}

复制代码

下面是​​BoardUser​​类,因为这个类主要是用来生成各类用于​​Socket​​接口传输的数据的,因此没有实现​​ibase​​接口,也没有进行登陆等操做,只有一个​​author​​来标记是不一样的做者,由于​​author​​这个参数在码的过程当中用到了。

package com.okayqa.board.function

import com.fun.utils.DecodeEncode
import com.okayqa.board.base.BoardBase
import com.okayqa.board.base.Document
import com.okayqa.board.base.Point
import com.okayqa.board.base.WriteType
import org.msgpack.core.MessagePack
import org.slf4j.Logger
import org.slf4j.LoggerFactory

import java.util.stream.Collectors

class BoardUser extends BoardBase {

private static Logger logger = LoggerFactory.getLogger(BoardUser.class)

/**
* 做者
*/
String author

/**
* 版本
*/
byte version = Document.BOARD_VERSION_INITIAL;

/**
* 最后一次点阵集合
*/
List<Point> ps;

BoardUser(String author) {
this.author = author
}

public String writeStart(List<Point> ps, String strokeId, byte page = 0) {
write(ps, strokeId, page, WriteType.START)
}


public String writeEnd(List<Point> ps, String strokeId, byte page = 0) {
write(ps, strokeId, page, WriteType.END)
}

public String writeMove(List<Point> ps, String strokeId, byte page = 0) {
write(ps, strokeId, page, WriteType.MOVE)
}

public String clearPage(byte page = 0) {
def packer = MessagePack.newDefaultBufferPacker()
writeClearPage(Document.CURRENT_BOARD_VERSION, author, page, packer);
DecodeEncode.base64Encode(packer.toByteArray())
}

/**
* 建立不一样的笔画类型
* @param ps
* @param strokeId
* @param page
* @param type
* @return
*/
private String write(List<Point> ps, String strokeId, byte page = 0, WriteType type) {
def packer = MessagePack.newDefaultBufferPacker()
switch (type) {
case WriteType.START:
writeStartWrite(version, author, page, strokeId, getColor(), ps, packer)
break;
case WriteType.MOVE:
writeContinueWrite(version, author, page, strokeId, ps, packer)
break
case WriteType.END:
writeEndWrite(version, author, page, strokeId, ps, packer)
break
default:
break
}
DecodeEncode.base64Encode(packer.toByteArray());
}

public List<String> initGraph(String strokeId = getStrokeId(), byte page = 0) {
List<String> mgss = new ArrayList<>()
if (ps == null || ps.isEmpty()) return mgss
for (int i = 0; i < ps.size(); i += 5) {
def five = ps[i..(i + 6 > ps.size() ? ps.size() - 1 : i + 4)]
if (mgss.isEmpty()) {
mgss << writeStart(five, strokeId, page)
continue
}
if (!mgss.isEmpty() && i + 6 > ps.size()) {
mgss << writeEnd(five, strokeId, page)
continue
}
mgss << writeMove(five, strokeId, page)
}
mgss
}


/**
* 画方形
* @return
*/
public List<String> writeSquare() {
ps = square(500, 300, 200, 100)
initGraph()
}

/**
* 画圆形
* @return
*/
public List<String> writeCircle() {
ps = circle(500, 300, 250)
initGraph()
}

/**
* 画心形
* @return
*/
public List<String> writeHeart() {
ps = heart(500, 300, 200)
initGraph()
}

/**
* 图形漂移
* @param offsetX
* @param offsetY
* @return
*/
public List<String> move(int offsetX, int offsetY) {
ps = ps.stream().map { it.move(offsetX, offsetY) }.collect(Collectors.toList())
initGraph()
}


}

复制代码

测试Demo

下面是测试方法:

public static void main(String[] args) throws IOException {
BoardUser boardUser = new BoardUser(Users.getTeaUser(0));
List<String> list = boardUser.writeCircle();
range(list.size()).forEach(x -> output(list.get(x)));
}
复制代码

控制台输出:

INFO-> 当前用户:fv,IP:10.60.193.37,工做目录:/Users/fv/Documents/workspace/okay_test/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO-> 生成了笔画ID: FunTester88f7b499-843d-406e-86f8-889c00119220
INFO-> AQKrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjDOAInvmZXNHUzNC7jNASzNHULNDDrNASzNHTjNDLzNASzNHSTNDT7NASzNHRDNDbbNASw=
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRzyzQ44zQEszRzKzQ66zQEszRyizQ8yzQEszRxwzQ+qzQEszRw0zRAizQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRv4zRCazQEszRuyzREIzQEszRtszRFszQEszRsczRHazQEszRrCzRI+zQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRpozRKYzQEszRoOzRLyzQEszRmqzRNMzQEszRk8zROczQEszRjYzRPizQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRhqzRQozQEszRfyzRRkzQEszRd6zRSgzQEszRcCzRTSzQEszRaKzRT6zQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRYIzRUizQEszRWGzRVAzQEszRUOzRVUzQEszRSMzRVozQEszRQKzRVyzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzROIzRV8zQEszRL8zRVyzQEszRJ6zRVozQEszRH4zRVUzQEszRGAzRVAzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRD+zRUizQEszRB8zRT6zQEszRAEzRTSzQEszQ+MzRSgzQEszQ8UzRRkzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQ6mzRQozQEszQ4uzRPizQEszQ3KzROczQEszQ1czRNMzQEszQz4zRLyzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQyezRKYzQEszQxEzRI+zQEszQvqzRHazQEszQuazRFszQEszQtUzREIzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQsOzRCazQEszQrSzRAizQEszQqWzQ+qzQEszQpkzQ8yzQEszQo8zQ66zQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQoUzQ44zQEszQn2zQ22zQEszQnizQ0+zQEszQnOzQy8zQEszQnEzQw6zQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQnEzQu4zQEszQnEzQsszQEszQnOzQqqzQEszQnizQoozQEszQn2zQmwzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQoUzQkuzQEszQo8zQiszQEszQpkzQg0zQEszQqWzQe8zQEszQrSzQdEzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQsOzQbWzQEszQtUzQZezQEszQuazQX6zQEszQvqzQWMzQEszQxEzQUozQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQyezQTOzQEszQz4zQR0zQEszQ1czQQazQEszQ3KzQPKzQEszQ4uzQOEzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzQ6czQM+zQEszQ8UzQMCzQEszQ+MzQLGzQEszRAEzQKUzQEszRB8zQJszQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRD+zQJEzQEszRGAzQImzQEszRH4zQISzQEszRJ6zQH+zQEszRL8zQH0zQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRN+zQH0zQEszRQKzQH0zQEszRSMzQH+zQEszRUOzQISzQEszRWGzQImzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRYIzQJEzQEszRaKzQJszQEszRcCzQKUzQEszRd6zQLGzQEszRfyzQMCzQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRhgzQM+zQEszRjYzQOEzQEszRk8zQPKzQEszRmqzQQazQEszRoOzQR0zQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRpozQTOzQEszRrCzQUozQEszRsczQWMzQEszRtszQX6zQEszRuyzQZezQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRv4zQbMzQEszRw0zQdEzQEszRxwzQe8zQEszRyizQg0zQEszRzKzQiszQEs
INFO-> AQOrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCVzRzyzQkuzQEszR0QzQmwzQEszR0kzQoozQEszR04zQqqzQEszR1CzQsszQEs
INFO-> AQSrNjE5NTEzNzUyNjkA2S1GdW5UZXN0ZXI4OGY3YjQ5OS04NDNkLTQwNmUtODZmOC04ODljMDAxMTkyMjCRzR1MzQuuzQEs

Process finished with exit code 0

复制代码

完美!

接下来会分享一下​​Socket​​接口的中如何进行白板接口测试,敬请期待!