mirror of
https://github.com/d07RiV/diabloweb.git
synced 2026-07-03 11:51:35 +00:00
server stuff
This commit is contained in:
2038
src/api/Diablo.jscc
2038
src/api/Diablo.jscc
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -4,6 +4,8 @@ import SpawnBinary from './DiabloSpawn.wasm';
|
|||||||
import SpawnModule from './DiabloSpawn.jscc';
|
import SpawnModule from './DiabloSpawn.jscc';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import websocket_open from './websocket';
|
||||||
|
|
||||||
const DiabloSize = 1466809;
|
const DiabloSize = 1466809;
|
||||||
const SpawnSize = 1337416;
|
const SpawnSize = 1337416;
|
||||||
|
|
||||||
@@ -16,6 +18,7 @@ let files = null;
|
|||||||
let renderBatch = null;
|
let renderBatch = null;
|
||||||
let drawBelt = null;
|
let drawBelt = null;
|
||||||
let is_spawn = false;
|
let is_spawn = false;
|
||||||
|
let websocket = null;
|
||||||
|
|
||||||
const ChunkSize = 1 << 20;
|
const ChunkSize = 1 << 20;
|
||||||
class RemoteFile {
|
class RemoteFile {
|
||||||
@@ -116,8 +119,35 @@ const DApi = {
|
|||||||
worker.postMessage({action: "keyboard", rect: null});
|
worker.postMessage({action: "keyboard", rect: null});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
use_websocket(flag) {
|
||||||
|
if (flag) {
|
||||||
|
if (!websocket || websocket.readyState !== 1) {
|
||||||
|
const sock = websocket = websocket_open('ws://diablo.rivsoft.net/', data => {
|
||||||
|
if (websocket === sock) {
|
||||||
|
try_api(() => {
|
||||||
|
const ptr = wasm._DApi_AllocPacket(data.byteLength);
|
||||||
|
wasm.HEAPU8.set(new Uint8Array(data), ptr);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, code => {
|
||||||
|
if (typeof code !== "number") {
|
||||||
|
worker.postMessage({action: "error", error: code.toString(), stack: code.stack});
|
||||||
|
code = 3;
|
||||||
|
}
|
||||||
|
call_api("SNet_WebsocketStatus", code);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
call_api("SNet_WebsocketStatus", 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (websocket) {
|
||||||
|
websocket.close();
|
||||||
|
}
|
||||||
|
websocket = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
websocket_closed() {
|
websocket_closed() {
|
||||||
return false;
|
return websocket ? websocket.readyState !== 1 : false;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -234,7 +264,9 @@ let maxSoundId = 0, maxBatchId = 0;
|
|||||||
|
|
||||||
let packetBatch = null;
|
let packetBatch = null;
|
||||||
DApi.websocket_send = function(data) {
|
DApi.websocket_send = function(data) {
|
||||||
if (packetBatch) {
|
if (websocket) {
|
||||||
|
websocket.send(data);
|
||||||
|
} else if (packetBatch) {
|
||||||
packetBatch.push(data.slice().buffer);
|
packetBatch.push(data.slice().buffer);
|
||||||
} else {
|
} else {
|
||||||
worker.postMessage({action: "packet", buffer: data});
|
worker.postMessage({action: "packet", buffer: data});
|
||||||
@@ -249,9 +281,6 @@ function try_api(func) {
|
|||||||
try {
|
try {
|
||||||
func();
|
func();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (typeof e === "string") {
|
|
||||||
worker.postMessage({action: ""})
|
|
||||||
}
|
|
||||||
worker.postMessage({action: "error", error: e.toString(), stack: e.stack});
|
worker.postMessage({action: "error", error: e.toString(), stack: e.stack});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
260
src/api/packet.js
Normal file
260
src/api/packet.js
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
export class buffer_reader {
|
||||||
|
constructor(buffer) {
|
||||||
|
this.buffer = (buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer));
|
||||||
|
this.pos = 0;
|
||||||
|
}
|
||||||
|
done() {
|
||||||
|
return this.pos === this.buffer.byteLength;
|
||||||
|
}
|
||||||
|
read8() {
|
||||||
|
if (this.pos >= this.buffer.byteLength) {
|
||||||
|
throw Error('packet too small');
|
||||||
|
}
|
||||||
|
return this.buffer[this.pos++];
|
||||||
|
}
|
||||||
|
read16() {
|
||||||
|
const {pos, buffer} = this;
|
||||||
|
if (pos + 2 > buffer.byteLength) {
|
||||||
|
throw Error('packet too small');
|
||||||
|
}
|
||||||
|
const result = buffer[pos] | (buffer[pos + 1] << 8);
|
||||||
|
this.pos += 2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
read32() {
|
||||||
|
const {pos, buffer} = this;
|
||||||
|
if (pos + 4 > buffer.byteLength) {
|
||||||
|
throw Error('packet too small');
|
||||||
|
}
|
||||||
|
const result = buffer[pos] | (buffer[pos + 1] << 8) | (buffer[pos + 2] << 16) | (buffer[pos + 3] << 24);
|
||||||
|
this.pos += 4;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
read_str() {
|
||||||
|
const length = this.read8();
|
||||||
|
const {pos, buffer} = this;
|
||||||
|
if (pos + length > buffer.byteLength) {
|
||||||
|
throw Error('packet too small');
|
||||||
|
}
|
||||||
|
const result = String.fromCharCode(...buffer.subarray(pos, pos + length));
|
||||||
|
this.pos += length;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
rest() {
|
||||||
|
const size = this.read32();
|
||||||
|
const result = this.buffer.subarray(this.pos, this.pos + size);
|
||||||
|
this.pos += size;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class buffer_writer {
|
||||||
|
constructor(length) {
|
||||||
|
this.buffer = new Uint8Array(length);
|
||||||
|
this.pos = 0;
|
||||||
|
}
|
||||||
|
get result() {
|
||||||
|
return this.buffer.buffer;
|
||||||
|
}
|
||||||
|
write8(value) {
|
||||||
|
this.buffer[this.pos++] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
write16(value) {
|
||||||
|
const {pos, buffer} = this;
|
||||||
|
buffer[pos] = value;
|
||||||
|
buffer[pos + 1] = value >> 8;
|
||||||
|
this.pos += 2;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
write32(value) {
|
||||||
|
const {pos, buffer} = this;
|
||||||
|
buffer[pos] = value;
|
||||||
|
buffer[pos + 1] = value >> 8;
|
||||||
|
buffer[pos + 2] = value >> 16;
|
||||||
|
buffer[pos + 3] = value >> 24;
|
||||||
|
this.pos += 4;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
write_str(value) {
|
||||||
|
const length = value.length;
|
||||||
|
this.write8(length);
|
||||||
|
const {pos, buffer} = this;
|
||||||
|
for (let i = 0; i < length; ++i) {
|
||||||
|
buffer[pos + i] = value.charCodeAt(i);
|
||||||
|
}
|
||||||
|
this.pos += length;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
rest(value) {
|
||||||
|
this.write32(value.byteLength);
|
||||||
|
this.buffer.set(value, this.pos);
|
||||||
|
this.pos += value.byteLength;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RejectionReason = {
|
||||||
|
JOIN_SUCCESS: 0x00,
|
||||||
|
JOIN_ALREADY_IN_GAME: 0x01,
|
||||||
|
JOIN_GAME_NOT_FOUND: 0x02,
|
||||||
|
JOIN_INCORRECT_PASSWORD: 0x03,
|
||||||
|
JOIN_VERSION_MISMATCH: 0x04,
|
||||||
|
JOIN_GAME_FULL: 0x05,
|
||||||
|
CREATE_GAME_EXISTS: 0x06,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function read_packet(reader, types) {
|
||||||
|
const code = reader.read8();
|
||||||
|
const cls = Object.values(types).find(cls => cls.code === code);
|
||||||
|
if (!cls) {
|
||||||
|
throw Error('invalid packet code');
|
||||||
|
}
|
||||||
|
return {type: cls, packet: cls.read(reader)};
|
||||||
|
}
|
||||||
|
export function packet_size(type, packet) {
|
||||||
|
return (typeof type.size === "function" ? type.size(packet) : type.size) + 1;
|
||||||
|
}
|
||||||
|
export function write_packet(type, packet) {
|
||||||
|
const size = packet_size(type, packet);
|
||||||
|
return type.write(new buffer_writer(size).write8(type.code), packet).result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function make_batch(types) {
|
||||||
|
return {
|
||||||
|
code: 0x00,
|
||||||
|
read: reader => {
|
||||||
|
const count = reader.read16();
|
||||||
|
const packets = [];
|
||||||
|
for (let i = 0; i < count; ++i) {
|
||||||
|
packets.push(read_packet(reader, types()));
|
||||||
|
}
|
||||||
|
return packets;
|
||||||
|
},
|
||||||
|
size: packets => packets.reduce((sum, {type, packet}) => sum + packet_size(type, packet), 2),
|
||||||
|
write: (writer, packets) => {
|
||||||
|
writer.write16(packets.length);
|
||||||
|
for (let {type, packet} of packets) {
|
||||||
|
type.write(writer.write8(type.code), packet);
|
||||||
|
}
|
||||||
|
return writer;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const server_packet = {
|
||||||
|
info: {
|
||||||
|
code: 0x32,
|
||||||
|
read: reader => ({version: reader.read32()}),
|
||||||
|
size: 4,
|
||||||
|
write: (writer, {version}) => writer.write32(version),
|
||||||
|
},
|
||||||
|
game_list: {
|
||||||
|
code: 0x21,
|
||||||
|
read: reader => {
|
||||||
|
const count = reader.read16();
|
||||||
|
const games = [];
|
||||||
|
for (let i = 0; i < count; ++i) {
|
||||||
|
games.push({type: reader.read32(), name: reader.read_str()});
|
||||||
|
}
|
||||||
|
return {games};
|
||||||
|
},
|
||||||
|
size: ({games}) => games.reduce((sum, {name}) => sum + 5 + name.length, 2),
|
||||||
|
write: (writer, {games}) => {
|
||||||
|
writer.write16(games.length);
|
||||||
|
for (let {type, name} of games) {
|
||||||
|
writer.write32(type);
|
||||||
|
writer.write_str(name);
|
||||||
|
}
|
||||||
|
return writer;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
join_accept: {
|
||||||
|
code: 0x12,
|
||||||
|
read: reader => ({cookie: reader.read32(), index: reader.read8(), seed: reader.read32(), difficulty: reader.read32()}),
|
||||||
|
size: 13,
|
||||||
|
write: (writer, {cookie, index, seed, difficulty}) => writer.write32(cookie).write8(index).write32(seed).write32(difficulty),
|
||||||
|
},
|
||||||
|
join_reject: {
|
||||||
|
code: 0x15,
|
||||||
|
read: reader => ({cookie: reader.read32(), reason: reader.read8()}),
|
||||||
|
size: 5,
|
||||||
|
write: (writer, {cookie, reason}) => writer.write32(cookie).write8(reason),
|
||||||
|
},
|
||||||
|
connect: {
|
||||||
|
code: 0x13,
|
||||||
|
read: reader => ({id: reader.read8()}),
|
||||||
|
size: 1,
|
||||||
|
write: (writer, {id}) => writer.write8(id),
|
||||||
|
},
|
||||||
|
disconnect: {
|
||||||
|
code: 0x14,
|
||||||
|
read: reader => ({id: reader.read8(), reason: reader.read32()}),
|
||||||
|
size: 5,
|
||||||
|
write: (writer, {id, reason}) => writer.write8(id).write32(reason),
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
code: 0x01,
|
||||||
|
read: reader => ({id: reader.read8(), payload: reader.rest()}),
|
||||||
|
size: ({payload}) => 5 + payload.byteLength,
|
||||||
|
write: (writer, {id, payload}) => writer.write8(id).rest(payload),
|
||||||
|
},
|
||||||
|
turn: {
|
||||||
|
code: 0x02,
|
||||||
|
read: reader => ({id: reader.read8(), turn: reader.read32()}),
|
||||||
|
size: 5,
|
||||||
|
write: (writer, {id, turn}) => writer.write8(id).write32(turn),
|
||||||
|
},
|
||||||
|
batch: make_batch(() => server_packet),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const client_packet = {
|
||||||
|
info: {
|
||||||
|
code: 0x31,
|
||||||
|
read: reader => ({version: reader.read32()}),
|
||||||
|
size: 4,
|
||||||
|
write: (writer, {version}) => writer.write32(version),
|
||||||
|
},
|
||||||
|
game_list: {
|
||||||
|
code: 0x21,
|
||||||
|
read: () => ({}),
|
||||||
|
size: 0,
|
||||||
|
write: writer => writer,
|
||||||
|
},
|
||||||
|
create_game: {
|
||||||
|
code: 0x22,
|
||||||
|
read: reader => ({cookie: reader.read32(), name: reader.read_str(), password: reader.read_str(), difficulty: reader.read32()}),
|
||||||
|
size: ({name, password}) => 10 + name.length + password.length,
|
||||||
|
write: (writer, {cookie, name, password, difficulty}) => writer.write32(cookie).write_str(name).write_str(password).write32(difficulty),
|
||||||
|
},
|
||||||
|
join_game: {
|
||||||
|
code: 0x23,
|
||||||
|
read: reader => ({cookie: reader.read32(), name: reader.read_str(), password: reader.read_str()}),
|
||||||
|
size: ({name, password}) => 6 + name.length + password.length,
|
||||||
|
write: (writer, {cookie, name, password}) => writer.write32(cookie).write_str(name).write_str(password),
|
||||||
|
},
|
||||||
|
leave_game: {
|
||||||
|
code: 0x24,
|
||||||
|
read: () => ({}),
|
||||||
|
size: 0,
|
||||||
|
write: writer => writer,
|
||||||
|
},
|
||||||
|
drop_player: {
|
||||||
|
code: 0x03,
|
||||||
|
read: reader => ({id: reader.read8(), reason: reader.read32()}),
|
||||||
|
size: 5,
|
||||||
|
write: (writer, {id, reason}) => writer.write8(id).write32(reason),
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
code: 0x01,
|
||||||
|
read: reader => ({id: reader.read8(), payload: reader.rest()}),
|
||||||
|
size: ({payload}) => 5 + payload.byteLength,
|
||||||
|
write: (writer, {id, payload}) => writer.write8(id).rest(payload),
|
||||||
|
},
|
||||||
|
turn: {
|
||||||
|
code: 0x02,
|
||||||
|
read: reader => ({turn: reader.read32()}),
|
||||||
|
size: 4,
|
||||||
|
write: (writer, {turn}) => writer.write32(turn),
|
||||||
|
},
|
||||||
|
batch: make_batch(() => server_packet),
|
||||||
|
};
|
||||||
@@ -1,210 +1,5 @@
|
|||||||
import Peer from 'peerjs';
|
import Peer from 'peerjs';
|
||||||
|
import { buffer_reader, read_packet, write_packet, client_packet, server_packet, RejectionReason } from './packet';
|
||||||
class buffer_reader {
|
|
||||||
constructor(buffer) {
|
|
||||||
this.buffer = (buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer));
|
|
||||||
this.pos = 0;
|
|
||||||
}
|
|
||||||
done() {
|
|
||||||
return this.pos === this.buffer.byteLength;
|
|
||||||
}
|
|
||||||
read8() {
|
|
||||||
if (this.pos >= this.buffer.byteLength) {
|
|
||||||
throw Error('packet too small');
|
|
||||||
}
|
|
||||||
return this.buffer[this.pos++];
|
|
||||||
}
|
|
||||||
read16() {
|
|
||||||
const {pos, buffer} = this;
|
|
||||||
if (pos + 2 > buffer.byteLength) {
|
|
||||||
throw Error('packet too small');
|
|
||||||
}
|
|
||||||
const result = buffer[pos] | (buffer[pos + 1] << 8);
|
|
||||||
this.pos += 2;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
read32() {
|
|
||||||
const {pos, buffer} = this;
|
|
||||||
if (pos + 4 > buffer.byteLength) {
|
|
||||||
throw Error('packet too small');
|
|
||||||
}
|
|
||||||
const result = buffer[pos] | (buffer[pos + 1] << 8) | (buffer[pos + 2] << 16) | (buffer[pos + 3] << 24);
|
|
||||||
this.pos += 4;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
read_str() {
|
|
||||||
const length = this.read8();
|
|
||||||
const {pos, buffer} = this;
|
|
||||||
if (pos + length > buffer.byteLength) {
|
|
||||||
throw Error('packet too small');
|
|
||||||
}
|
|
||||||
const result = String.fromCharCode(...buffer.subarray(pos, pos + length));
|
|
||||||
this.pos += length;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
rest() {
|
|
||||||
const result = this.buffer.subarray(this.pos);
|
|
||||||
this.pos = this.buffer.length;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class buffer_writer {
|
|
||||||
constructor(length) {
|
|
||||||
this.buffer = new Uint8Array(length);
|
|
||||||
this.pos = 0;
|
|
||||||
}
|
|
||||||
get result() {
|
|
||||||
return this.buffer.buffer;
|
|
||||||
}
|
|
||||||
write8(value) {
|
|
||||||
this.buffer[this.pos++] = value;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
write16(value) {
|
|
||||||
const {pos, buffer} = this;
|
|
||||||
buffer[pos] = value;
|
|
||||||
buffer[pos + 1] = value >> 8;
|
|
||||||
this.pos += 2;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
write32(value) {
|
|
||||||
const {pos, buffer} = this;
|
|
||||||
buffer[pos] = value;
|
|
||||||
buffer[pos + 1] = value >> 8;
|
|
||||||
buffer[pos + 2] = value >> 16;
|
|
||||||
buffer[pos + 3] = value >> 24;
|
|
||||||
this.pos += 4;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
write_str(value) {
|
|
||||||
const length = value.length;
|
|
||||||
this.write8(length);
|
|
||||||
const {pos, buffer} = this;
|
|
||||||
for (let i = 0; i < length; ++i) {
|
|
||||||
buffer[pos + i] = value.charCodeAt(i);
|
|
||||||
}
|
|
||||||
this.pos += length;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
rest(value) {
|
|
||||||
this.buffer.set(value, this.pos);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const RejectionReason = {
|
|
||||||
JOIN_SUCCESS: 0x00,
|
|
||||||
JOIN_ALREADY_IN_GAME: 0x01,
|
|
||||||
JOIN_GAME_NOT_FOUND: 0x02,
|
|
||||||
JOIN_INCORRECT_PASSWORD: 0x03,
|
|
||||||
JOIN_VERSION_MISMATCH: 0x04,
|
|
||||||
JOIN_GAME_FULL: 0x05,
|
|
||||||
CREATE_GAME_EXISTS: 0x06,
|
|
||||||
};
|
|
||||||
|
|
||||||
const server_packet = {
|
|
||||||
info: {
|
|
||||||
code: 0x32,
|
|
||||||
read: reader => ({version: reader.read32()}),
|
|
||||||
write: ({version}) => new buffer_writer(5).write8(server_packet.info.code).write32(version).result,
|
|
||||||
},
|
|
||||||
game_list: {
|
|
||||||
code: 0x21,
|
|
||||||
read: reader => {
|
|
||||||
const count = reader.read8();
|
|
||||||
const games = [];
|
|
||||||
for (let i = 0; i < count; ++i) {
|
|
||||||
games.push({type: reader.read32(), name: reader.read_str()});
|
|
||||||
}
|
|
||||||
return {games};
|
|
||||||
},
|
|
||||||
write: ({games}) => {
|
|
||||||
const writer = new buffer_writer(games.reduce((sum, {name}) => sum + 5 + name.length, 2));
|
|
||||||
writer.write8(server_packet.game_list.code);
|
|
||||||
writer.write8(games.length);
|
|
||||||
for (let {code, name} of games) {
|
|
||||||
writer.write32(code);
|
|
||||||
writer.write_str(name);
|
|
||||||
}
|
|
||||||
return writer.result;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
join_accept: {
|
|
||||||
code: 0x12,
|
|
||||||
read: reader => ({cookie: reader.read32(), index: reader.read8(), seed: reader.read32(), difficulty: reader.read32()}),
|
|
||||||
write: ({cookie, index, seed, difficulty}) => new buffer_writer(14).write8(server_packet.join_accept.code).write32(cookie).write8(index).write32(seed).write32(difficulty).result,
|
|
||||||
},
|
|
||||||
join_reject: {
|
|
||||||
code: 0x15,
|
|
||||||
read: reader => ({cookie: reader.read32(), reason: reader.read8()}),
|
|
||||||
write: ({cookie, reason}) => new buffer_writer(6).write8(server_packet.join_reject.code).write32(cookie).write8(reason).result,
|
|
||||||
},
|
|
||||||
connect: {
|
|
||||||
code: 0x13,
|
|
||||||
read: reader => ({id: reader.read8()}),
|
|
||||||
write: ({id}) => new buffer_writer(2).write8(server_packet.connect.code).write8(id).result,
|
|
||||||
},
|
|
||||||
disconnect: {
|
|
||||||
code: 0x14,
|
|
||||||
read: reader => ({id: reader.read8(), reason: reader.read32()}),
|
|
||||||
write: ({id, reason}) => new buffer_writer(6).write8(server_packet.disconnect.code).write8(id).write32(reason).result,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
code: 0x01,
|
|
||||||
read: reader => ({id: reader.read8(), payload: reader.rest()}),
|
|
||||||
write: ({id, payload}) => new buffer_writer(2 + payload.byteLength).write8(server_packet.message.code).write8(id).rest(payload).result,
|
|
||||||
},
|
|
||||||
turn: {
|
|
||||||
code: 0x02,
|
|
||||||
read: reader => ({id: reader.read8(), turn: reader.read32()}),
|
|
||||||
write: ({id, turn}) => new buffer_writer(6).write8(server_packet.turn.code).write8(id).write32(turn).result,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const client_packet = {
|
|
||||||
info: {
|
|
||||||
code: 0x31,
|
|
||||||
read: reader => ({version: reader.read32()}),
|
|
||||||
write: ({version}) => new buffer_writer(5).write8(client_packet.info.code).write32(version).result,
|
|
||||||
},
|
|
||||||
game_list: {
|
|
||||||
code: 0x21,
|
|
||||||
read: () => ({}),
|
|
||||||
write: () => new buffer_writer(1).write8(client_packet.game_list.code).result,
|
|
||||||
},
|
|
||||||
create_game: {
|
|
||||||
code: 0x22,
|
|
||||||
read: reader => ({cookie: reader.read32(), name: reader.read_str(), password: reader.read_str(), difficulty: reader.read32()}),
|
|
||||||
write: ({cookie, name, password, difficulty}) => new buffer_writer(11 + name.length + password.length)
|
|
||||||
.write8(client_packet.create_game.code).write32(cookie).write_str(name).write_str(password).write32(difficulty).result,
|
|
||||||
},
|
|
||||||
join_game: {
|
|
||||||
code: 0x23,
|
|
||||||
read: reader => ({cookie: reader.read32(), name: reader.read_str(), password: reader.read_str()}),
|
|
||||||
write: ({cookie, name, password}) => new buffer_writer(7 + name.length + password.length)
|
|
||||||
.write8(client_packet.join_game.code).write32(cookie).write_str(name).write_str(password).result,
|
|
||||||
},
|
|
||||||
leave_game: {
|
|
||||||
code: 0x24,
|
|
||||||
read: () => ({}),
|
|
||||||
write: () => new buffer_writer(1).write8(client_packet.leave_game.code).result,
|
|
||||||
},
|
|
||||||
drop_player: {
|
|
||||||
code: 0x03,
|
|
||||||
read: reader => ({id: reader.read8(), reason: reader.read32()}),
|
|
||||||
write: ({id, reason}) => new buffer_writer(6).write8(client_packet.drop_player.code).write8(id).write32(reason).result,
|
|
||||||
},
|
|
||||||
message: {
|
|
||||||
code: 0x01,
|
|
||||||
read: reader => ({id: reader.read8(), payload: reader.rest()}),
|
|
||||||
write: ({id, payload}) => new buffer_writer(2 + payload.byteLength).write8(client_packet.message.code).write8(id).rest(payload).result,
|
|
||||||
},
|
|
||||||
turn: {
|
|
||||||
code: 0x02,
|
|
||||||
read: reader => ({turn: reader.read32()}),
|
|
||||||
write: ({turn}) => new buffer_writer(5).write8(client_packet.turn.code).write32(turn).result,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/*function log_packet(data, type) {
|
/*function log_packet(data, type) {
|
||||||
const reader = new buffer_reader(data);
|
const reader = new buffer_reader(data);
|
||||||
@@ -262,15 +57,12 @@ class webrtc_server {
|
|||||||
const peer = {conn};
|
const peer = {conn};
|
||||||
conn.on('data', packet => {
|
conn.on('data', packet => {
|
||||||
const reader = new buffer_reader(packet);
|
const reader = new buffer_reader(packet);
|
||||||
const code = reader.read8();
|
const {type, packet: pkt} = read_packet(reader, client_packet);
|
||||||
let pkt;
|
switch (type.code) {
|
||||||
switch (code) {
|
|
||||||
case client_packet.info.code:
|
case client_packet.info.code:
|
||||||
pkt = client_packet.info.read(reader);
|
|
||||||
peer.version = pkt.version;
|
peer.version = pkt.version;
|
||||||
break;
|
break;
|
||||||
case client_packet.join_game.code:
|
case client_packet.join_game.code:
|
||||||
pkt = client_packet.join_game.read(reader);
|
|
||||||
if (peer.version !== this.version) {
|
if (peer.version !== this.version) {
|
||||||
conn.send(server_packet.join_reject.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_VERSION_MISMATCH}));
|
conn.send(server_packet.join_reject.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_VERSION_MISMATCH}));
|
||||||
} else if (pkt.name !== this.name) {
|
} else if (pkt.name !== this.name) {
|
||||||
@@ -294,7 +86,7 @@ class webrtc_server {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (peer.id != null) {
|
if (peer.id != null) {
|
||||||
this.handle(peer.id, code, reader);
|
this.handle(peer.id, type.code, pkt);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -343,23 +135,18 @@ class webrtc_server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handle(id, code, reader) {
|
handle(id, code, pkt) {
|
||||||
let pkt;
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case client_packet.leave_game.code:
|
case client_packet.leave_game.code:
|
||||||
pkt = client_packet.leave_game.read(reader);
|
|
||||||
this.drop(id, 3);
|
this.drop(id, 3);
|
||||||
break;
|
break;
|
||||||
case client_packet.drop_player.code:
|
case client_packet.drop_player.code:
|
||||||
pkt = client_packet.drop_player.read(reader);
|
|
||||||
this.drop(pkt.id, pkt.reason);
|
this.drop(pkt.id, pkt.reason);
|
||||||
break;
|
break;
|
||||||
case client_packet.message.code:
|
case client_packet.message.code:
|
||||||
pkt = client_packet.message.read(reader);
|
|
||||||
this.send(pkt.id === 0xFF ? ~(1 << id) : (1 << pkt.id), server_packet.message.write({id, payload: pkt.payload}));
|
this.send(pkt.id === 0xFF ? ~(1 << id) : (1 << pkt.id), server_packet.message.write({id, payload: pkt.payload}));
|
||||||
break;
|
break;
|
||||||
case client_packet.turn.code:
|
case client_packet.turn.code:
|
||||||
pkt = client_packet.turn.read(reader);
|
|
||||||
this.send(~(1 << id), server_packet.turn.write({id, turn: pkt.turn}));
|
this.send(~(1 << id), server_packet.turn.write({id, turn: pkt.turn}));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -411,18 +198,15 @@ class webrtc_client {
|
|||||||
this.conn.on('data', data => {
|
this.conn.on('data', data => {
|
||||||
unreg();
|
unreg();
|
||||||
const reader = new buffer_reader(data);
|
const reader = new buffer_reader(data);
|
||||||
const code = reader.read8();
|
const {type, packet: pkt} = read_packet(reader, server_packet);
|
||||||
let pkt;
|
switch (type.code) {
|
||||||
switch (code) {
|
|
||||||
case server_packet.join_accept.code:
|
case server_packet.join_accept.code:
|
||||||
pkt = server_packet.join_accept.read(reader);
|
|
||||||
this.myplr = pkt.index;
|
this.myplr = pkt.index;
|
||||||
break;
|
break;
|
||||||
case server_packet.join_reject.code:
|
case server_packet.join_reject.code:
|
||||||
onClose();
|
onClose();
|
||||||
break;
|
break;
|
||||||
case server_packet.disconnect.code:
|
case server_packet.disconnect.code:
|
||||||
pkt = server_packet.disconnect.read(reader);
|
|
||||||
if (pkt.id === 'myplr') {
|
if (pkt.id === 'myplr') {
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
@@ -460,15 +244,12 @@ export default function webrtc_open(onMessage) {
|
|||||||
send: function(packet) {
|
send: function(packet) {
|
||||||
//log_packet(packet, client_packet);
|
//log_packet(packet, client_packet);
|
||||||
const reader = new buffer_reader(packet);
|
const reader = new buffer_reader(packet);
|
||||||
const code = reader.read8();
|
const {type, packet: pkt} = read_packet(reader, client_packet);
|
||||||
let pkt;
|
switch (type.code) {
|
||||||
switch (code) {
|
|
||||||
case client_packet.info.code:
|
case client_packet.info.code:
|
||||||
pkt = client_packet.info.read(reader);
|
|
||||||
version = pkt.version;
|
version = pkt.version;
|
||||||
break;
|
break;
|
||||||
case client_packet.create_game.code:
|
case client_packet.create_game.code:
|
||||||
pkt = client_packet.create_game.read(reader);
|
|
||||||
if (server || client) {
|
if (server || client) {
|
||||||
onMessage(server_packet.join_reject.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_ALREADY_IN_GAME}));
|
onMessage(server_packet.join_reject.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_ALREADY_IN_GAME}));
|
||||||
} else {
|
} else {
|
||||||
@@ -476,7 +257,6 @@ export default function webrtc_open(onMessage) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case client_packet.join_game.code:
|
case client_packet.join_game.code:
|
||||||
pkt = client_packet.join_game.read(reader);
|
|
||||||
if (server || client) {
|
if (server || client) {
|
||||||
onMessage(server_packet.join_reject.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_ALREADY_IN_GAME}));
|
onMessage(server_packet.join_reject.write({cookie: pkt.cookie, reason: RejectionReason.JOIN_ALREADY_IN_GAME}));
|
||||||
} else {
|
} else {
|
||||||
@@ -485,18 +265,18 @@ export default function webrtc_open(onMessage) {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (server) {
|
if (server) {
|
||||||
server.handle(0, code, reader);
|
server.handle(0, type.code, pkt);
|
||||||
if (code === client_packet.leave_game.code) {
|
if (type.code === client_packet.leave_game.code) {
|
||||||
server = null;
|
server = null;
|
||||||
}
|
}
|
||||||
} else if (client) {
|
} else if (client) {
|
||||||
client.send(packet);
|
client.send(packet);
|
||||||
if (code === client_packet.leave_game.code) {
|
if (type.code === client_packet.leave_game.code) {
|
||||||
client = null;
|
client = null;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (code !== client_packet.leave_game.code) {
|
} else if (type.code !== client_packet.leave_game.code) {
|
||||||
throw Error(`invalid packet ${code}`);
|
throw Error(`invalid packet ${type.code}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!reader.done()) {
|
if (!reader.done()) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export default async function websocket_open(url, handler) {
|
async function do_websocket_open(url, handler) {
|
||||||
const socket = new WebSocket(url);
|
const socket = new WebSocket(url);
|
||||||
socket.binaryType = "arraybuffer";
|
socket.binaryType = "arraybuffer";
|
||||||
let versionCbk = null;
|
let versionCbk = null;
|
||||||
@@ -9,7 +9,7 @@ export default async function websocket_open(url, handler) {
|
|||||||
handler(data);
|
handler(data);
|
||||||
});
|
});
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const onError = err => reject(err);
|
const onError = err => reject(1);
|
||||||
socket.addEventListener("error", onError);
|
socket.addEventListener("error", onError);
|
||||||
socket.addEventListener("open", () => {
|
socket.addEventListener("open", () => {
|
||||||
socket.removeEventListener("error", onError);
|
socket.removeEventListener("error", onError);
|
||||||
@@ -19,7 +19,7 @@ export default async function websocket_open(url, handler) {
|
|||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const to = setTimeout(() => {
|
const to = setTimeout(() => {
|
||||||
versionCbk = null;
|
versionCbk = null;
|
||||||
reject(Error("connection timed out"));
|
reject(1);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
versionCbk = data => {
|
versionCbk = data => {
|
||||||
clearTimeout(to);
|
clearTimeout(to);
|
||||||
@@ -30,7 +30,7 @@ export default async function websocket_open(url, handler) {
|
|||||||
if (version === 1) {
|
if (version === 1) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
reject("server version mismatch");
|
reject(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -46,3 +46,40 @@ export default async function websocket_open(url, handler) {
|
|||||||
socket.send(clientInfo);
|
socket.send(clientInfo);
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function websocket_open(url, handler, finisher) {
|
||||||
|
let ws = null, pending = [];
|
||||||
|
const proxy = {
|
||||||
|
get readyState() {
|
||||||
|
return ws ? ws.readyState : 0;
|
||||||
|
},
|
||||||
|
send(msg) {
|
||||||
|
if (ws) {
|
||||||
|
ws.send(msg);
|
||||||
|
} else {
|
||||||
|
pending.push(msg.slice());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
if (ws) {
|
||||||
|
ws.close();
|
||||||
|
} else {
|
||||||
|
pending = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
do_websocket_open(url, handler).then(sock => {
|
||||||
|
ws = sock;
|
||||||
|
if (pending) {
|
||||||
|
for (let msg of pending) {
|
||||||
|
ws.send(msg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
|
finisher(0);
|
||||||
|
}, err => {
|
||||||
|
finisher(err);
|
||||||
|
});
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user