Replace session create with challenge.
This commit is contained in:
parent
44ef10e6c2
commit
cd9a0aea2c
@ -66,7 +66,7 @@ impl App {
|
||||
let user = filesystem.user_fetch(id as u32).unwrap();
|
||||
|
||||
// Add user to contests if flag is set.
|
||||
if (user.flags & user::F_CONTEST) != 0 {
|
||||
if (user.flags & user::FC_ENABLE) != 0 {
|
||||
match contests.binary_search(&user.id) {
|
||||
Ok(_) => { }
|
||||
Err(pos) => { contests.insert(pos, user.id); }
|
||||
@ -135,6 +135,13 @@ impl App {
|
||||
} else { None }
|
||||
}
|
||||
|
||||
pub fn get_user_by_id_mut(&mut self, id:u32) -> Option<&mut User>
|
||||
{
|
||||
if let Some(uid) = self.user_id.get(id as isize) {
|
||||
self.users.get_mut(*uid)
|
||||
} else { None }
|
||||
}
|
||||
|
||||
pub async fn send_response(&mut self, response:QRPacket)
|
||||
{
|
||||
use crate::protocol::*;
|
||||
@ -178,15 +185,9 @@ impl App {
|
||||
)).await.ok();
|
||||
}
|
||||
|
||||
QRPacketData::RSessionCreate(response) => {
|
||||
QRPacketData::RSessionView(response) => {
|
||||
socket.send(Message::Binary(
|
||||
encode_response(CODE_SESSION_CREATE, response.encode())
|
||||
)).await.ok();
|
||||
}
|
||||
|
||||
QRPacketData::RSessionJoin(response) => {
|
||||
socket.send(Message::Binary(
|
||||
encode_response(CODE_SESSION_JOIN, response.encode())
|
||||
encode_response(CODE_SESSION_VIEW, response.encode())
|
||||
)).await.ok();
|
||||
}
|
||||
|
||||
@ -202,6 +203,24 @@ impl App {
|
||||
)).await.ok();
|
||||
}
|
||||
|
||||
QRPacketData::RChallengeAnswer(response) => {
|
||||
socket.send(Message::Binary(
|
||||
encode_response(CODE_CHALLENGE_ANSWER, response.encode())
|
||||
)).await.ok();
|
||||
}
|
||||
|
||||
QRPacketData::RChallengeList(response) => {
|
||||
socket.send(Message::Binary(
|
||||
encode_response(CODE_CHALLENGE_LIST, response.encode())
|
||||
)).await.ok();
|
||||
}
|
||||
|
||||
QRPacketData::RUserList(response) => {
|
||||
socket.send(Message::Binary(
|
||||
encode_response(CODE_USER_LIST, response.encode())
|
||||
)).await.ok();
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,16 @@
|
||||
pub const F_CONTEST :u32 = 0x0000_0001;
|
||||
pub const FC_ENABLE :u32 = 0x0000_0001;
|
||||
|
||||
pub struct UserStatus {
|
||||
pub await_flags:u32,
|
||||
}
|
||||
impl UserStatus {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
await_flags:0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct User {
|
||||
pub id:u32,
|
||||
@ -6,4 +18,7 @@ pub struct User {
|
||||
pub handle:String,
|
||||
pub secret:Vec<u8>,
|
||||
pub na_key:u32,
|
||||
|
||||
pub status:UserStatus,
|
||||
pub challenges:Vec<u32>,
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -104,7 +104,7 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
}
|
||||
|
||||
CODE_SESSION_CREATE => match PacketSessionCreate::decode(&data, &mut index) {
|
||||
/*CODE_SESSION_JOIN => match PacketSessionCreate::decode(&data, &mut index) {
|
||||
Ok(packet) => {
|
||||
args.bus.send(
|
||||
bus_ds,
|
||||
@ -112,13 +112,13 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
|
||||
).ok();
|
||||
}
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
}
|
||||
}*/
|
||||
|
||||
CODE_SESSION_JOIN => match PacketSessionJoin::decode(&data, &mut index) {
|
||||
CODE_SESSION_VIEW => match PacketSessionView::decode(&data, &mut index) {
|
||||
Ok(packet) => {
|
||||
args.bus.send(
|
||||
bus_ds,
|
||||
QRPacket::new(conn_id, QRPacketData::QSessionJoin(packet))
|
||||
QRPacket::new(conn_id, QRPacketData::QSessionView(packet))
|
||||
).ok();
|
||||
}
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
@ -161,6 +161,40 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
}
|
||||
|
||||
CODE_CHALLENGE => match PacketChallenge::decode(&data, &mut index) {
|
||||
Ok(packet) => {
|
||||
args.bus.send(
|
||||
bus_ds,
|
||||
QRPacket::new(conn_id, QRPacketData::QChallenge(packet))
|
||||
).ok();
|
||||
}
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
}
|
||||
|
||||
CODE_CHALLENGE_ANSWER => match PacketChallengeAnswer::decode(&data, &mut index) {
|
||||
Ok(packet) => {
|
||||
args.bus.send(
|
||||
bus_ds,
|
||||
QRPacket::new(conn_id, QRPacketData::QChallengeAnswer(packet))
|
||||
).ok();
|
||||
}
|
||||
Err(_) => { println!("error: packet decode failed."); }
|
||||
}
|
||||
|
||||
CODE_CHALLENGE_LIST => {
|
||||
args.bus.send(
|
||||
bus_ds,
|
||||
QRPacket::new(conn_id, QRPacketData::QChallengeList)
|
||||
).ok();
|
||||
}
|
||||
|
||||
CODE_USER_LIST => {
|
||||
args.bus.send(
|
||||
bus_ds,
|
||||
QRPacket::new(conn_id, QRPacketData::QUserList)
|
||||
).ok();
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
true
|
||||
|
@ -3,9 +3,13 @@
|
||||
*/
|
||||
|
||||
pub const STATUS_OK :u16 = 0x0000;
|
||||
|
||||
pub const STATUS_ERROR :u16 = 0x0001;
|
||||
pub const STATUS_NOAUTH :u16 = 0x0002;
|
||||
|
||||
pub const STATUS_APPROVE :u16 = 0x0003;
|
||||
pub const STATUS_REJECT :u16 = 0x0004;
|
||||
|
||||
pub const STATUS_BAD_HANDLE :u16 = 0x0010;
|
||||
pub const STATUS_BAD_SECRET :u16 = 0x0011;
|
||||
pub const STATUS_BAD_CODE :u16 = 0x0012;
|
||||
@ -24,10 +28,18 @@ pub const CODE_AUTH_RESUME :u16 = 0x0012;
|
||||
pub const CODE_AUTH_REVOKE :u16 = 0x0013;
|
||||
|
||||
pub const CODE_SESSION_LIST :u16 = 0x0020;
|
||||
pub const CODE_SESSION_CREATE :u16 = 0x0021;
|
||||
pub const CODE_SESSION_JOIN :u16 = 0x0022;
|
||||
pub const CODE_SESSION_JOIN :u16 = 0x0021;
|
||||
pub const CODE_SESSION_VIEW :u16 = 0x0022;
|
||||
pub const CODE_SESSION_RETIRE :u16 = 0x002E;
|
||||
pub const CODE_SESSION_LEAVE :u16 = 0x002F;
|
||||
|
||||
pub const CODE_GAME_STATE :u16 = 0x0030;
|
||||
pub const CODE_GAME_PLAY :u16 = 0x0031;
|
||||
|
||||
pub const CODE_CHALLENGE :u16 = 0x0060;
|
||||
pub const CODE_CHALLENGE_ANSWER :u16 = 0x0061;
|
||||
pub const CODE_CHALLENGE_LIST :u16 = 0x0062;
|
||||
|
||||
pub const CODE_USER_LIST :u16 = 0x0100;
|
||||
//pub const CODE_USER_AWAIT_GET :u16 = 0x0110;
|
||||
//pub const CODE_USER_AWAIT_SET :u16 = 0x0111;
|
||||
|
@ -23,17 +23,14 @@ pub enum QRPacketData {
|
||||
|
||||
QAuthRevoke,
|
||||
|
||||
QUserList(PacketUserList),
|
||||
QUserList,
|
||||
RUserList(PacketUserListResponse),
|
||||
|
||||
QSessionList(PacketSessionList),
|
||||
RSessionList(PacketSessionListResponse),
|
||||
|
||||
QSessionCreate(PacketSessionCreate),
|
||||
RSessionCreate(PacketSessionCreateResponse),
|
||||
|
||||
QSessionJoin(PacketSessionJoin),
|
||||
RSessionJoin(PacketSessionJoinResponse),
|
||||
QSessionView(PacketSessionView),
|
||||
RSessionView(PacketSessionViewResponse),
|
||||
|
||||
QSessionRetire(PacketSessionRetire),
|
||||
|
||||
@ -43,6 +40,14 @@ pub enum QRPacketData {
|
||||
RGameState(PacketGameStateResponse),
|
||||
|
||||
QGamePlay(PacketGamePlay),
|
||||
|
||||
QChallenge(PacketChallenge),
|
||||
|
||||
QChallengeAnswer(PacketChallengeAnswer),
|
||||
RChallengeAnswer(PacketChallengeAnswerResponse),
|
||||
|
||||
QChallengeList,
|
||||
RChallengeList(PacketChallengeListResponse),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
38
server/src/protocol/packet/challenge.rs
Normal file
38
server/src/protocol/packet/challenge.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::util::pack::unpack_u8;
|
||||
|
||||
use super::Packet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketChallenge {
|
||||
pub handle:String,
|
||||
}
|
||||
impl PacketChallenge {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
handle:String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Packet for PacketChallenge {
|
||||
type Data = Self;
|
||||
|
||||
fn decode(data:&Vec<u8>, index:&mut usize) -> Result<Self::Data, ()>
|
||||
{
|
||||
let mut result = Self::new();
|
||||
|
||||
let length = unpack_u8(data, index) as usize;
|
||||
let mut buffer = vec![0u8; length];
|
||||
if data.len() - *index >= length {
|
||||
for i in 0..length {
|
||||
buffer[i] = data[*index];
|
||||
*index += 1;
|
||||
}
|
||||
|
||||
result.handle = String::from_utf8(buffer).map_err(|_| ())?;
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
73
server/src/protocol/packet/challenge_answer.rs
Normal file
73
server/src/protocol/packet/challenge_answer.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use crate::{
|
||||
app::session::SessionToken,
|
||||
util::pack::{unpack_u8, pack_u16},
|
||||
};
|
||||
|
||||
use super::Packet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketChallengeAnswer {
|
||||
pub handle:String,
|
||||
pub answer:bool,
|
||||
}
|
||||
impl PacketChallengeAnswer {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
handle:String::new(),
|
||||
answer:false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Packet for PacketChallengeAnswer {
|
||||
type Data = Self;
|
||||
|
||||
fn decode(data:&Vec<u8>, index:&mut usize) -> Result<Self::Data, ()>
|
||||
{
|
||||
let mut result = Self::new();
|
||||
|
||||
result.answer = unpack_u8(data, index) != 0;
|
||||
|
||||
let length = unpack_u8(data, index) as usize;
|
||||
let mut buffer = vec![0u8; length];
|
||||
if data.len() - *index >= length {
|
||||
for i in 0..length {
|
||||
buffer[i] = data[*index];
|
||||
*index += 1;
|
||||
}
|
||||
|
||||
result.handle = String::from_utf8(buffer).map_err(|_| ())?;
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketChallengeAnswerResponse {
|
||||
pub status:u16,
|
||||
pub token:SessionToken,
|
||||
}
|
||||
impl PacketChallengeAnswerResponse {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
status:0,
|
||||
token:SessionToken::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Packet for PacketChallengeAnswerResponse {
|
||||
type Data = Self;
|
||||
|
||||
fn encode(&self) -> Vec<u8>
|
||||
{
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
buffer.append(&mut pack_u16(self.status));
|
||||
buffer.append(&mut self.token.to_vec());
|
||||
|
||||
buffer
|
||||
}
|
||||
}
|
46
server/src/protocol/packet/challenge_list.rs
Normal file
46
server/src/protocol/packet/challenge_list.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use crate::util::pack::{pack_u8, pack_u16};
|
||||
|
||||
use super::Packet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketChallengeListData {
|
||||
pub handle:String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketChallengeListResponse {
|
||||
pub status:u16,
|
||||
pub challenges:Vec<PacketChallengeListData>,
|
||||
}
|
||||
impl PacketChallengeListResponse {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
status:0,
|
||||
challenges:Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Packet for PacketChallengeListResponse {
|
||||
type Data = Self;
|
||||
|
||||
fn encode(&self) -> Vec<u8>
|
||||
{
|
||||
let mut buffer = pack_u16(self.status);
|
||||
|
||||
// Records
|
||||
buffer.append(&mut pack_u16(self.challenges.len() as u16));
|
||||
for challenge in &self.challenges {
|
||||
let mut chunk = Vec::new();
|
||||
|
||||
// Handle
|
||||
let mut bytes = challenge.handle.as_bytes().to_vec();
|
||||
chunk.append(&mut pack_u8(bytes.len() as u8));
|
||||
chunk.append(&mut bytes);
|
||||
|
||||
buffer.append(&mut chunk);
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
}
|
@ -4,17 +4,21 @@ mod register; pub use register::*;
|
||||
mod auth; pub use auth::*;
|
||||
mod resume; pub use resume::*;
|
||||
|
||||
mod user_list; pub use user_list::*;
|
||||
|
||||
mod session_list; pub use session_list::*;
|
||||
mod session_create; pub use session_create::*;
|
||||
mod session_join; pub use session_join::*;
|
||||
//mod session_create; pub use session_create::*;
|
||||
mod session_view; pub use session_view::*;
|
||||
mod session_retire; pub use session_retire::*;
|
||||
|
||||
mod game_state; pub use game_state::*;
|
||||
mod game_play; pub use game_play::*;
|
||||
//mod game_history; pub use game_history::*;
|
||||
|
||||
mod challenge; pub use challenge::*;
|
||||
mod challenge_answer; pub use challenge_answer::*;
|
||||
mod challenge_list; pub use challenge_list::*;
|
||||
|
||||
mod user_list; pub use user_list::*;
|
||||
|
||||
mod prelude {
|
||||
pub trait Packet {
|
||||
type Data;
|
||||
|
@ -6,11 +6,11 @@ use crate::{
|
||||
use super::Packet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketSessionJoin {
|
||||
pub struct PacketSessionView {
|
||||
pub token:SessionToken,
|
||||
pub join:bool,
|
||||
}
|
||||
impl PacketSessionJoin {
|
||||
impl PacketSessionView {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
@ -19,7 +19,7 @@ impl PacketSessionJoin {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Packet for PacketSessionJoin {
|
||||
impl Packet for PacketSessionView {
|
||||
type Data = Self;
|
||||
|
||||
fn decode(data:&Vec<u8>, index:&mut usize) -> Result<Self::Data, ()>
|
||||
@ -38,11 +38,11 @@ impl Packet for PacketSessionJoin {
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketSessionJoinResponse {
|
||||
pub struct PacketSessionViewResponse {
|
||||
pub status:u16,
|
||||
pub token:SessionToken,
|
||||
}
|
||||
impl PacketSessionJoinResponse {
|
||||
impl PacketSessionViewResponse {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
@ -51,7 +51,7 @@ impl PacketSessionJoinResponse {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Packet for PacketSessionJoinResponse {
|
||||
impl Packet for PacketSessionViewResponse {
|
||||
type Data = Self;
|
||||
|
||||
fn encode(&self) -> Vec<u8>
|
@ -1,47 +1,16 @@
|
||||
use crate::util::pack::{pack_u16, unpack_u16};
|
||||
use crate::util::pack::{pack_u8, pack_u16};
|
||||
|
||||
use super::Packet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketUserList {
|
||||
pub page:u16,
|
||||
}
|
||||
impl PacketUserList {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
page:0,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Packet for PacketUserList {
|
||||
type Data = Self;
|
||||
|
||||
fn decode(data:&Vec<u8>, index:&mut usize) -> Result<Self::Data, ()>
|
||||
{
|
||||
let mut result = Self::new();
|
||||
|
||||
if data.len() - *index == 2 {
|
||||
result.page = unpack_u16(data, index);
|
||||
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketUserListResponseRecord {
|
||||
//pub token:UserToken,
|
||||
pub struct PacketUserListData {
|
||||
pub handle:String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PacketUserListResponse {
|
||||
pub status:u16,
|
||||
pub records:Vec<PacketUserListResponseRecord>,
|
||||
pub records:Vec<PacketUserListData>,
|
||||
}
|
||||
impl PacketUserListResponse {
|
||||
pub fn new() -> Self
|
||||
@ -59,15 +28,15 @@ impl Packet for PacketUserListResponse {
|
||||
{
|
||||
let mut result = pack_u16(self.status as u16);
|
||||
|
||||
// Records
|
||||
result.append(&mut pack_u16(self.records.len() as u16));
|
||||
|
||||
for record in &self.records {
|
||||
let mut chunk = Vec::new(); //record.token.to_vec();
|
||||
let mut chunk = Vec::new();
|
||||
|
||||
// Handle
|
||||
let mut bytes = record.handle.as_bytes().to_vec();
|
||||
chunk.append(&mut pack_u16(bytes.len() as u16));
|
||||
if bytes.len() > 0 { chunk.append(&mut bytes); }
|
||||
chunk.append(&mut pack_u8(bytes.len() as u8));
|
||||
chunk.append(&mut bytes);
|
||||
|
||||
result.append(&mut chunk);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use game::{
|
||||
use crate::{
|
||||
app::{
|
||||
session::{Session, SessionToken, SessionSecret},
|
||||
user::User,
|
||||
user::{User, UserStatus},
|
||||
},
|
||||
util::pack::*,
|
||||
};
|
||||
@ -19,8 +19,10 @@ const HANDLE_BUCKET_MASK :u32 = 0xFF;
|
||||
const HANDLE_BUCKET_SIZE :u32 = HANDLE_BUCKET_MASK + 1;
|
||||
|
||||
const GENERIC_CONFIG :&str = "c.bin";
|
||||
const GENERIC_INDEX :&str = "i.bin";
|
||||
const GENERIC_HISTORY :&str = "h.bin";
|
||||
const GENERIC_INDEX :&str = "i.bin";
|
||||
const GENERIC_REQUEST :&str = "r.bin";
|
||||
const GENERIC_STATUS :&str = "s.bin";
|
||||
|
||||
const DIR_DATA :&str = "data";
|
||||
const DIR_HANDLE :&str = const_format::formatcp!("{}/h", DIR_DATA);
|
||||
@ -93,7 +95,7 @@ impl FileSystem {
|
||||
}
|
||||
|
||||
|
||||
pub fn session_store(&mut self, session:&Session) -> Result<u32,()>
|
||||
pub fn session_create(&mut self, session:&Session) -> Result<u32,()>
|
||||
{
|
||||
let size = self.session_count()? as u32;
|
||||
|
||||
@ -284,7 +286,7 @@ impl FileSystem {
|
||||
}
|
||||
|
||||
|
||||
pub fn user_store(&mut self, user:&User) -> Result<u32,()>
|
||||
pub fn user_create(&mut self, user:&User) -> Result<u32,()>
|
||||
{
|
||||
let size = self.user_count()? as u32;
|
||||
|
||||
@ -295,14 +297,14 @@ impl FileSystem {
|
||||
self.index_user.seek(SeekFrom::Start(0)).map_err(|_| ())?;
|
||||
self.index_user.write(&pack_u32(size + 1)).map_err(|_| ())?;
|
||||
|
||||
// Create bucket file if not exists
|
||||
let bucket_path = Path::new(DIR_USER).join(format!("{:08x}", bucket_index));
|
||||
if !bucket_path.exists() {
|
||||
fs::create_dir(bucket_path.clone()).map_err(|_| ())?;
|
||||
}
|
||||
// Create user directory
|
||||
let bucket_path = Path::new(DIR_USER)
|
||||
.join(format!("{:08x}", bucket_index))
|
||||
.join(format!("{:08x}", file_index));
|
||||
fs::create_dir_all(bucket_path.clone()).map_err(|_| ())?;
|
||||
|
||||
// Open bucket file for record
|
||||
let file_path = bucket_path.join(format!("{:08x}.bin", file_index));
|
||||
// Create configuration file
|
||||
let file_path = bucket_path.join(GENERIC_CONFIG);
|
||||
if let Ok(mut file) = File::options().write(true).create(true).open(file_path) {
|
||||
|
||||
let handle = user.handle.as_bytes().to_vec();
|
||||
@ -314,9 +316,35 @@ impl FileSystem {
|
||||
file.write(&user.secret).map_err(|_| ())?;
|
||||
file.write(&pack_u8(handle.len() as u8)).map_err(|_| ())?;
|
||||
file.write(&handle).map_err(|_| ())?;
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
} else { Err(()) }
|
||||
// Create status file
|
||||
let file_path = bucket_path.join(GENERIC_STATUS);
|
||||
if let Ok(mut file) = File::options().write(true).create(true).open(file_path) {
|
||||
|
||||
let extra_buffer = [0u8; 12];
|
||||
|
||||
let contest = 0;
|
||||
|
||||
// Write user information
|
||||
file.write(&pack_u32(contest)).map_err(|_| ())?;
|
||||
file.write(&extra_buffer).map_err(|_| ())?;
|
||||
}
|
||||
|
||||
// Create challenges file
|
||||
let file_path = bucket_path.join(GENERIC_REQUEST);
|
||||
if let Ok(mut file) = File::options().write(true).create(true).open(file_path) {
|
||||
|
||||
// Write requests count
|
||||
file.write(&pack_u16(0)).map_err(|_| ())?;
|
||||
}
|
||||
|
||||
Ok(size)
|
||||
}
|
||||
|
||||
pub fn user_update_status(&mut self) -> Result<(),()>
|
||||
{
|
||||
Err(())
|
||||
}
|
||||
|
||||
pub fn user_fetch(&mut self, id:u32) -> Result<User,()>
|
||||
@ -329,7 +357,8 @@ impl FileSystem {
|
||||
// Open bucket file for record
|
||||
let file_path = Path::new(DIR_USER)
|
||||
.join(format!("{:08x}", bucket_index))
|
||||
.join(format!("{:08x}.bin", file_index));
|
||||
.join(format!("{:08x}", file_index))
|
||||
.join(GENERIC_CONFIG);
|
||||
|
||||
if let Ok(mut file) = File::options().read(true).open(file_path) {
|
||||
file.seek(SeekFrom::Start(0)).map_err(|_| ())?;
|
||||
@ -365,6 +394,9 @@ impl FileSystem {
|
||||
handle,
|
||||
secret,
|
||||
na_key,
|
||||
|
||||
status:UserStatus::new(),
|
||||
challenges:Vec::new(),
|
||||
})
|
||||
} else { Err(()) }
|
||||
}
|
||||
@ -377,7 +409,7 @@ impl FileSystem {
|
||||
}
|
||||
|
||||
|
||||
pub fn handle_store(&mut self, handle:&String, user_id:u32) -> Result<u32,()>
|
||||
pub fn handle_create(&mut self, handle:&String, user_id:u32) -> Result<u32,()>
|
||||
// Add a salt to store.
|
||||
//
|
||||
{
|
||||
@ -474,7 +506,7 @@ impl FileSystem {
|
||||
}
|
||||
|
||||
|
||||
pub fn salt_store(&mut self, salt:[u8; 16]) -> Result<u32,()>
|
||||
pub fn salt_create(&mut self, salt:[u8; 16]) -> Result<u32,()>
|
||||
// Add a salt to store.
|
||||
//
|
||||
{
|
||||
|
@ -16,7 +16,10 @@ main.form>section>div{
|
||||
max-width:30rem;
|
||||
padding:0.5rem;
|
||||
|
||||
font-size: 1.2rem;
|
||||
|
||||
background-color:#303030;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
main.form>section>div>table{
|
||||
@ -36,7 +39,7 @@ main.form>section>div>table label{
|
||||
color:#e0e0e0;
|
||||
}
|
||||
|
||||
main.form>section>div>table input{
|
||||
main.form>section>div>table input[type="text"], main.form>section>div>table input[type="password"]{
|
||||
display:block;
|
||||
position:relative;
|
||||
width:100%;
|
||||
@ -81,3 +84,7 @@ main.form>section>div>button:disabled{
|
||||
color:#606060;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
main.form>section>div input[type="checkbox"] {
|
||||
height:1.5em;
|
||||
}
|
||||
|
@ -12,30 +12,38 @@ let CONTEXT = {
|
||||
};
|
||||
|
||||
const Status = {
|
||||
Ok: 0x0000,
|
||||
Error: 0x0001,
|
||||
NotImplemented: 0x0002,
|
||||
Ok :0x0000,
|
||||
Error :0x0001,
|
||||
NotImplemented :0x0002,
|
||||
Approve :0x0003,
|
||||
Reject :0x0004,
|
||||
|
||||
BadHandle: 0x0010,
|
||||
BadSecret: 0x0011,
|
||||
BadCode: 0x0012,
|
||||
BadHandle :0x0010,
|
||||
BadSecret :0x0011,
|
||||
BadCode :0x0012,
|
||||
};
|
||||
|
||||
const OpCode = {
|
||||
Register :0x0010,
|
||||
Authenticate :0x0011,
|
||||
Resume :0x0012,
|
||||
Deauthenticate :0x0013,
|
||||
Register :0x0010,
|
||||
Authenticate :0x0011,
|
||||
Resume :0x0012,
|
||||
Deauthenticate :0x0013,
|
||||
|
||||
SessionList :0x0020,
|
||||
SessionCreate :0x0021,
|
||||
SessionJoin :0x0022,
|
||||
SessionRetire :0x002E,
|
||||
SessionLeave :0x002F,
|
||||
SessionList :0x0020,
|
||||
//SessionJoin :0x0021,
|
||||
SessionView :0x0022,
|
||||
SessionRetire :0x002E,
|
||||
SessionLeave :0x002F,
|
||||
|
||||
GameState :0x0030,
|
||||
GamePlay :0x0031,
|
||||
GameHistory :0x0032,
|
||||
GameState :0x0030,
|
||||
GamePlay :0x0031,
|
||||
GameHistory :0x0032,
|
||||
|
||||
Challenge :0x0060,
|
||||
ChallengeAnswer :0x0061,
|
||||
ChallengeList :0x0062,
|
||||
|
||||
UserList :0x0100,
|
||||
};
|
||||
|
||||
const GameState = {
|
||||
|
@ -798,8 +798,7 @@ const INTERFACE = {
|
||||
|
||||
switch(code) {
|
||||
|
||||
case OpCode.SessionCreate:
|
||||
case OpCode.SessionJoin: {
|
||||
case OpCode.SessionView: {
|
||||
if(data.status != Status.Ok) {
|
||||
LOAD(SCENES.Browse);
|
||||
}
|
||||
|
233
www/js/scene.js
233
www/js/scene.js
@ -280,12 +280,6 @@ const SCENES = {
|
||||
table.appendChild(UI.session_table(data.records));
|
||||
}
|
||||
} break;
|
||||
case OpCode.SessionCreate:
|
||||
case OpCode.SessionJoin: {
|
||||
if(data.status == Status.Ok) {
|
||||
LOAD(SCENES.Game, data);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
@ -293,7 +287,7 @@ const SCENES = {
|
||||
},
|
||||
},
|
||||
|
||||
Join:{
|
||||
/*Join:{
|
||||
load() {
|
||||
if(sessionStorage.getItem("auth") === null) return false;
|
||||
|
||||
@ -337,8 +331,7 @@ const SCENES = {
|
||||
table.appendChild(UI.session_table_join(data.records));
|
||||
}
|
||||
} break;
|
||||
case OpCode.SessionCreate:
|
||||
case OpCode.SessionJoin: {
|
||||
case OpCode.SessionView: {
|
||||
if(data.status == Status.Ok) {
|
||||
LOAD(SCENES.Game, data);
|
||||
}
|
||||
@ -348,7 +341,7 @@ const SCENES = {
|
||||
disconnect() {
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
},*/
|
||||
|
||||
Live:{
|
||||
load() {
|
||||
@ -392,11 +385,6 @@ const SCENES = {
|
||||
table.appendChild(UI.session_table(data.records));
|
||||
}
|
||||
} break;
|
||||
{
|
||||
if(data.status == Status.Ok) {
|
||||
LOAD(SCENES.Game, data);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
@ -542,8 +530,7 @@ const SCENES = {
|
||||
]
|
||||
);
|
||||
|
||||
let slider = UI.slider((event) => { INTERFACE.replay_jump(event.target.value); });
|
||||
slider.setAttribute("id", "turn-slider");
|
||||
let slider = UI.slider("turn-slider", (event) => { INTERFACE.replay_jump(event.target.value); });
|
||||
slider.setAttribute("min", "0");
|
||||
slider.setAttribute("max", "0");
|
||||
MAIN.appendChild(UI.div([ slider ], "turn-slider-padding"));
|
||||
@ -564,7 +551,7 @@ const SCENES = {
|
||||
message(code, data) {
|
||||
switch(code) {
|
||||
case OpCode.SessionCreate:
|
||||
case OpCode.SessionJoin:
|
||||
case OpCode.SessionView:
|
||||
case OpCode.GameState:
|
||||
case OpCode.GamePlay: {
|
||||
INTERFACE.message(code, data);
|
||||
@ -601,6 +588,216 @@ const SCENES = {
|
||||
INTERFACE.uninit();
|
||||
},
|
||||
},
|
||||
|
||||
Await:{
|
||||
load() {
|
||||
if(sessionStorage.getItem("auth") === null) return false;
|
||||
UI.mainmenu("await");
|
||||
UI.mainnav([], [], { session:true });
|
||||
|
||||
let container = document.createElement("section");
|
||||
let form = document.createElement("div");
|
||||
form.appendChild(UI.text("Await a challenger:"));
|
||||
form.appendChild(UI.table(null, [
|
||||
[ UI.label("Accepting", "in-accept"), UI.checkbox("in-accept") ],
|
||||
]));
|
||||
|
||||
let button = UI.button("Update", (event) => {
|
||||
let accepting = 0;
|
||||
if(document.getElementById("in-accept").value == "on") {
|
||||
accepting = 1;
|
||||
}
|
||||
|
||||
let flags = 0;
|
||||
flags |= accepting;
|
||||
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.UserAwait),
|
||||
PACK.u32(flags),
|
||||
]);
|
||||
|
||||
LOAD_URL();
|
||||
});
|
||||
form.appendChild(button);
|
||||
|
||||
container.appendChild(form);
|
||||
MAIN.appendChild(container);
|
||||
MAIN.setAttribute("class", "form");
|
||||
|
||||
return true;
|
||||
},
|
||||
disconnect() {
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
Challenge:{
|
||||
load() {
|
||||
CONTEXT.Data = {
|
||||
page:0,
|
||||
records:[],
|
||||
};
|
||||
|
||||
UI.mainmenu("browse");
|
||||
UI.mainnav(
|
||||
[
|
||||
UI.button("Users", () => { LOAD(SCENES.Challenge); }),
|
||||
UI.button("Requests", () => { LOAD(SCENES.ChallengeList); }),
|
||||
],
|
||||
[
|
||||
UI.div([UI.text("0 - 0 of 0")]),
|
||||
UI.button("◀", null),
|
||||
UI.button("▶", null),
|
||||
UI.button("Refresh", null),
|
||||
]
|
||||
);
|
||||
|
||||
let table = document.createElement("table");
|
||||
table.setAttribute("id", "content");
|
||||
table.setAttribute("class", "list");
|
||||
MAIN.appendChild(table);
|
||||
|
||||
SCENE.refresh();
|
||||
|
||||
history.pushState(null, "Omen", "/challenge/");
|
||||
return true;
|
||||
},
|
||||
refresh() {
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.UserList),
|
||||
]);
|
||||
},
|
||||
message(code, data) {
|
||||
switch(code) {
|
||||
case OpCode.UserList: {
|
||||
let table = document.getElementById("content");
|
||||
UI.clear(table);
|
||||
|
||||
if(data !== null) {
|
||||
let rows = [ ];
|
||||
|
||||
for(let r = 0; r < data.users.length; ++r) {
|
||||
let buttons = [ ];
|
||||
|
||||
let callback = function() {
|
||||
MESSAGE_CHALLENGE(this.handle);
|
||||
};
|
||||
callback = callback.bind({handle: data.users[r].handle});
|
||||
buttons.push(UI.button("Challenge", callback));
|
||||
|
||||
rows.push([
|
||||
UI.text(data.users[r].handle),
|
||||
buttons,
|
||||
]);
|
||||
}
|
||||
|
||||
let tbody = UI.table_content(
|
||||
[ "User", "" ],
|
||||
rows,
|
||||
);
|
||||
|
||||
table.appendChild(tbody);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
|
||||
ChallengeList:{
|
||||
load() {
|
||||
CONTEXT.Data = {
|
||||
page:0,
|
||||
records:[],
|
||||
};
|
||||
|
||||
UI.mainmenu("browse");
|
||||
UI.mainnav(
|
||||
[
|
||||
UI.button("Users", () => { LOAD(SCENES.Challenge); }),
|
||||
UI.button("Requests", () => { LOAD(SCENES.ChallengeList); }),
|
||||
],
|
||||
[
|
||||
UI.div([UI.text("0 - 0 of 0")]),
|
||||
UI.button("◀", null),
|
||||
UI.button("▶", null),
|
||||
UI.button("Refresh", null),
|
||||
]
|
||||
);
|
||||
|
||||
let table = document.createElement("table");
|
||||
table.setAttribute("id", "content");
|
||||
table.setAttribute("class", "list");
|
||||
MAIN.appendChild(table);
|
||||
|
||||
SCENE.refresh();
|
||||
|
||||
history.pushState(null, "Omen", "/challenge/");
|
||||
return true;
|
||||
},
|
||||
refresh() {
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.ChallengeList),
|
||||
]);
|
||||
},
|
||||
message(code, data) {
|
||||
switch(code) {
|
||||
case OpCode.ChallengeList: {
|
||||
let table = document.getElementById("content");
|
||||
UI.clear(table);
|
||||
|
||||
if(data !== null) {
|
||||
let rows = [ ];
|
||||
|
||||
for(let r = 0; r < data.challenges.length; ++r) {
|
||||
let buttons = [ ];
|
||||
|
||||
let callback_accept = function() {
|
||||
MESSAGE_CHALLENGE_ANSWER(this.handle, true);
|
||||
};
|
||||
callback_accept = callback_accept.bind({handle: data.challenges[r].handle});
|
||||
buttons.push(UI.button("Accept", callback_accept));
|
||||
|
||||
let callback_reject = function() {
|
||||
MESSAGE_CHALLENGE_ANSWER(this.handle, false);
|
||||
};
|
||||
callback_reject = callback_reject.bind({handle: data.challenges[r].handle});
|
||||
buttons.push(UI.button("Reject", callback_reject));
|
||||
|
||||
rows.push([
|
||||
UI.text(data.challenges[r].handle),
|
||||
buttons,
|
||||
]);
|
||||
}
|
||||
|
||||
let tbody = UI.table_content(
|
||||
[ "User", "" ],
|
||||
rows,
|
||||
);
|
||||
|
||||
table.appendChild(tbody);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OpCode.ChallengeAnswer: {
|
||||
if(data.status == Status.Ok) {
|
||||
|
||||
LOAD(SCENES.Game, {
|
||||
token:data.token,
|
||||
mode:INTERFACE.Mode.Player,
|
||||
});
|
||||
} else {
|
||||
SCENE.refresh();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
},
|
||||
disconnect() {
|
||||
LOAD(SCENES.Offline);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function LOAD(scene, data=null) {
|
||||
|
104
www/js/system.js
104
www/js/system.js
@ -181,8 +181,7 @@ function MESSAGE(event) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case OpCode.SessionCreate:
|
||||
case OpCode.SessionJoin: {
|
||||
case OpCode.SessionView: {
|
||||
console.log("RECV SessionCreate/Join");
|
||||
|
||||
if(bytes.length - index == 10) {
|
||||
@ -278,6 +277,80 @@ function MESSAGE(event) {
|
||||
data.play.to = (result.data >> 10) & 0x3F;
|
||||
} break;
|
||||
|
||||
case OpCode.ChallengeAnswer: {
|
||||
data = {
|
||||
status:0,
|
||||
token:new Uint8Array(8),
|
||||
};
|
||||
|
||||
// Status
|
||||
result = UNPACK.u16(bytes, index);
|
||||
index = result.index;
|
||||
data.status = result.data;
|
||||
|
||||
for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; }
|
||||
} break;
|
||||
|
||||
case OpCode.ChallengeList: {
|
||||
data = {
|
||||
status:0,
|
||||
challenges:[ ],
|
||||
};
|
||||
|
||||
// Status
|
||||
result = UNPACK.u16(bytes, index);
|
||||
index = result.index;
|
||||
data.status = result.data;
|
||||
|
||||
// Records
|
||||
result = UNPACK.u16(bytes, index);
|
||||
index = result.index;
|
||||
let length = result.data;
|
||||
|
||||
for(let i = 0; i < length; ++i) {
|
||||
let record = {
|
||||
handle:"",
|
||||
};
|
||||
|
||||
// Handle
|
||||
result = UNPACK.string(bytes, index, UNPACK.u8);
|
||||
index = result.index;
|
||||
record.handle = result.data;
|
||||
|
||||
data.challenges.push(record);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OpCode.UserList: {
|
||||
data = {
|
||||
status:0,
|
||||
users:[ ],
|
||||
};
|
||||
|
||||
// Status
|
||||
result = UNPACK.u16(bytes, index);
|
||||
index = result.index;
|
||||
data.status = result.data;
|
||||
|
||||
// Records
|
||||
result = UNPACK.u16(bytes, index);
|
||||
index = result.index;
|
||||
let length = result.data;
|
||||
|
||||
for(let i = 0; i < length; ++i) {
|
||||
let record = {
|
||||
handle:"",
|
||||
};
|
||||
|
||||
// Handle
|
||||
result = UNPACK.string(bytes, index, UNPACK.u8);
|
||||
index = result.index;
|
||||
record.handle = result.data;
|
||||
|
||||
data.users.push(record);
|
||||
}
|
||||
} break;
|
||||
|
||||
default:
|
||||
console.log("RECV Undefined " + code);
|
||||
return;
|
||||
@ -318,16 +391,27 @@ function MESSAGE_SESSION_LIST(page, game_state, is_player, is_live) {
|
||||
]);
|
||||
}
|
||||
|
||||
function MESSAGE_SESSION_START() {
|
||||
function MESSAGE_SESSION_VIEW(token, player) {
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.SessionCreate),
|
||||
]);
|
||||
}
|
||||
|
||||
function MESSAGE_SESSION_JOIN(token, player) {
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.SessionJoin),
|
||||
PACK.u16(OpCode.SessionView),
|
||||
token,
|
||||
PACK.u8(player),
|
||||
]);
|
||||
}
|
||||
|
||||
function MESSAGE_CHALLENGE(handle) {
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.Challenge),
|
||||
PACK.string(handle, PACK.u8),
|
||||
]);
|
||||
}
|
||||
|
||||
function MESSAGE_CHALLENGE_ANSWER(handle, answer) {
|
||||
console.log(handle + " " + answer);
|
||||
|
||||
MESSAGE_COMPOSE([
|
||||
PACK.u16(OpCode.ChallengeAnswer),
|
||||
PACK.u8(+answer),
|
||||
PACK.string(handle, PACK.u8),
|
||||
]);
|
||||
}
|
||||
|
41
www/js/ui.js
41
www/js/ui.js
@ -11,14 +11,23 @@ const UI = {
|
||||
return button;
|
||||
},
|
||||
|
||||
slider(callback) {
|
||||
let slider = document.createElement("input");
|
||||
slider.setAttribute("type", "range");
|
||||
slider.setAttribute("value", "0");
|
||||
slider.setAttribute("min", "0");
|
||||
slider.setAttribute("max", "0");
|
||||
if(callback !== null) { slider.addEventListener("input", callback); }
|
||||
return slider;
|
||||
slider(id, callback) {
|
||||
let input = document.createElement("input");
|
||||
if(id !== null) { input.setAttribute("id", id); }
|
||||
input.setAttribute("type", "range");
|
||||
input.setAttribute("value", "0");
|
||||
input.setAttribute("min", "0");
|
||||
input.setAttribute("max", "0");
|
||||
if(callback !== null) { input.addEventListener("input", callback); }
|
||||
return input;
|
||||
},
|
||||
|
||||
checkbox(id, callback) {
|
||||
let input = document.createElement("input");
|
||||
if(id !== null) { input.setAttribute("id", id); }
|
||||
input.setAttribute("type", "checkbox");
|
||||
if(callback !== null) { input.addEventListener("change", callback); }
|
||||
return input;
|
||||
},
|
||||
|
||||
textbox(id, placeholder) {
|
||||
@ -101,8 +110,8 @@ const UI = {
|
||||
}
|
||||
} else {
|
||||
if(features.session === true) {
|
||||
left.appendChild(UI.button("Contest", () => { MESSAGE_SESSION_START(); }));
|
||||
left.appendChild(UI.button("Challenge", () => { }));
|
||||
//left.appendChild(UI.button("Await", () => { }));
|
||||
left.appendChild(UI.button("Challenge", () => { LOAD(SCENES.Challenge); }));
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +144,7 @@ const UI = {
|
||||
top.push(UI.button("Browse", () => { LOAD(SCENES.Browse); }, page == "browse"));
|
||||
if(sessionStorage.getItem("auth") !== null) {
|
||||
top.push(UI.button("Continue", () => { LOAD(SCENES.Continue); }, page == "continue"));
|
||||
top.push(UI.button("Join", () => { LOAD(SCENES.Join); }, page == "join"));
|
||||
//top.push(UI.button("Join", () => { LOAD(SCENES.Join); }, page == "join"));
|
||||
}
|
||||
top.push(UI.button("Live", () => { LOAD(SCENES.Live); }, page == "live"));
|
||||
top.push(UI.button("History", () => { LOAD(SCENES.History); }, page == "history"));
|
||||
@ -167,7 +176,7 @@ const UI = {
|
||||
token:this.token,
|
||||
mode:INTERFACE.Mode.Player,
|
||||
});
|
||||
MESSAGE_SESSION_JOIN(this.token, true);
|
||||
MESSAGE_SESSION_VIEW(this.token, true);
|
||||
};
|
||||
join_callback = join_callback.bind({token: records[r].token});
|
||||
|
||||
@ -176,7 +185,7 @@ const UI = {
|
||||
token:this.token,
|
||||
mode:INTERFACE.Mode.Review,
|
||||
});
|
||||
MESSAGE_SESSION_JOIN(this.token, false);
|
||||
MESSAGE_SESSION_VIEW(this.token, false);
|
||||
};
|
||||
spectate_callback = spectate_callback.bind({token: records[r].token});
|
||||
|
||||
@ -223,7 +232,7 @@ const UI = {
|
||||
token:this.token,
|
||||
mode:INTERFACE.Mode.Player,
|
||||
});
|
||||
MESSAGE_SESSION_JOIN(this.token, true);
|
||||
MESSAGE_SESSION_VIEW(this.token, true);
|
||||
};
|
||||
join_callback = join_callback.bind({token: records[r].token});
|
||||
|
||||
@ -260,7 +269,7 @@ const UI = {
|
||||
token:this.token,
|
||||
mode:INTERFACE.Mode.Review,
|
||||
});
|
||||
MESSAGE_SESSION_JOIN(this.token, false);
|
||||
MESSAGE_SESSION_VIEW(this.token, false);
|
||||
};
|
||||
view_callback = view_callback.bind({token: records[r].token});
|
||||
|
||||
@ -289,7 +298,7 @@ const UI = {
|
||||
},
|
||||
|
||||
clear(dom) {
|
||||
while(dom.lastChild !== null) { dom.removeChild(document.body.lastChild); }
|
||||
while(dom.lastChild !== null) { dom.removeChild(dom.lastChild); }
|
||||
},
|
||||
|
||||
rebuild() {
|
||||
|
@ -13,6 +13,19 @@ const PACK = {
|
||||
value & 0xFF
|
||||
]);
|
||||
},
|
||||
string(text, pack) {
|
||||
let enc = new TextEncoder();
|
||||
let bytes = enc.encode(text);
|
||||
let size_bytes = pack(bytes.length);
|
||||
|
||||
let length = size_bytes.length + bytes.length;
|
||||
|
||||
let result = new Uint8Array(length);
|
||||
result.set(size_bytes, 0);
|
||||
result.set(bytes, size_bytes.length);
|
||||
|
||||
return result;
|
||||
},
|
||||
base64(bytes) {
|
||||
let str = "";
|
||||
for(let i = 0; i < bytes.length; ++i) {
|
||||
@ -50,8 +63,8 @@ const UNPACK = {
|
||||
}
|
||||
return { data: result, index: index };
|
||||
},
|
||||
string(data, index) {
|
||||
let result = UNPACK.u16(data, index);
|
||||
string(data, index, unpack=UNPACK.u16) {
|
||||
let result = unpack(data, index);
|
||||
index = result.index;
|
||||
let length = result.data;
|
||||
|
||||
@ -66,7 +79,7 @@ const UNPACK = {
|
||||
index += length;
|
||||
|
||||
result_str = dec.decode(bytes);
|
||||
} else { console.log("INV DATA LEN"); }
|
||||
} else { console.log("error: unexpected end of data (" + data.length + " / " + length + ")"); }
|
||||
|
||||
return { data: result_str, index: index };
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user