-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor to remove extend event target
- Loading branch information
1 parent
6f994b1
commit eb36802
Showing
2 changed files
with
190 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,195 +1,211 @@ | ||
import { messages } from "./message"; | ||
import { ServerConfig, State, WebsocketConnectingError, WebsocketError, WebsocketTimeoutError } from "./types"; | ||
import { | ||
Event, | ||
EventListener, | ||
ServerConfig, | ||
State, | ||
WebsocketConnectingError, | ||
WebsocketError, | ||
WebsocketTimeoutError, | ||
} from "./types"; | ||
import { parseReceivedPayload } from "./util"; | ||
|
||
class WebsocketStatusChangedEvent extends Event { | ||
constructor() { | ||
super("websocketStatusChanged"); | ||
} | ||
} | ||
export class VeadotubeClient { | ||
private config: ServerConfig; | ||
public websocket: WebSocket | null; | ||
private veadotubeStates: State[]; | ||
private currentStateId: string | null; | ||
private timeoutTimerId: number | null; | ||
|
||
class StatesChangedEvent extends Event { | ||
constructor() { | ||
super("statesChanged"); | ||
} | ||
} | ||
private subscribers: { | ||
[key in Event]: Set<EventListener>; | ||
} = { | ||
websocketStatusChanged: new Set(), | ||
statesChanged: new Set(), | ||
stateChanged: new Set(), | ||
}; | ||
|
||
class StateChangedEvent extends Event { | ||
constructor() { | ||
super("stateChanged"); | ||
} | ||
} | ||
constructor(config: ServerConfig) { | ||
this.config = config; | ||
|
||
this.websocket = null; | ||
this.veadotubeStates = []; | ||
this.currentStateId = null; | ||
|
||
export class VeadotubeClient extends EventTarget { | ||
private config: ServerConfig; | ||
public websocket: WebSocket | null; | ||
private veadotubeStates: State[]; | ||
private currentStateId: string | null; | ||
private timeoutTimerId: number | null; | ||
this.timeoutTimerId = null; | ||
} | ||
|
||
constructor(config: ServerConfig) { | ||
super(); | ||
this.config = config; | ||
addEventListener = (type: Event, listener: EventListener) => { | ||
this.subscribers[type].add(listener); | ||
}; | ||
|
||
this.websocket = null; | ||
this.veadotubeStates = []; | ||
this.currentStateId = null; | ||
removeEventListener = (type: Event, listener: EventListener) => { | ||
this.subscribers[type].delete(listener); | ||
}; | ||
|
||
this.timeoutTimerId = null; | ||
dispatchEvent(event: Event): void { | ||
for (const listener of this.subscribers[event]) { | ||
listener(); | ||
} | ||
} | ||
|
||
reset = () => { | ||
this.stopTimeoutTimer(); | ||
|
||
this.websocket = null; | ||
this.veadotubeStates = []; | ||
this.currentStateId = null; | ||
|
||
this.dispatchEvent(new WebsocketStatusChangedEvent()); | ||
this.dispatchEvent(new StatesChangedEvent()); | ||
this.dispatchEvent(new StateChangedEvent()); | ||
} | ||
reset = () => { | ||
this.stopTimeoutTimer(); | ||
|
||
startTimeoutTimer = () => { | ||
if (this.timeoutTimerId) { | ||
return | ||
} | ||
this.websocket = null; | ||
this.veadotubeStates = []; | ||
this.currentStateId = null; | ||
|
||
this.timeoutTimerId = window.setTimeout(() => { | ||
if(this.config.onErrorCallback) { | ||
this.config.onErrorCallback(WebsocketTimeoutError); | ||
} else { | ||
console.error("timeout occurred"); | ||
} | ||
}, 3000); | ||
} | ||
this.dispatchEvent("websocketStatusChanged"); | ||
this.dispatchEvent("statesChanged"); | ||
this.dispatchEvent("stateChanged"); | ||
}; | ||
|
||
stopTimeoutTimer = () => { | ||
if (this.timeoutTimerId) { | ||
clearTimeout(this.timeoutTimerId); | ||
this.timeoutTimerId = null; | ||
} | ||
startTimeoutTimer = () => { | ||
if (this.timeoutTimerId) { | ||
return; | ||
} | ||
|
||
onMessage = (event: MessageEvent<string>) => { | ||
this.stopTimeoutTimer() | ||
const payloadEventResult = parseReceivedPayload(event); | ||
this.timeoutTimerId = window.setTimeout(() => { | ||
if (this.config.onErrorCallback) { | ||
this.config.onErrorCallback(WebsocketTimeoutError); | ||
} else { | ||
console.error("timeout occurred"); | ||
} | ||
}, 3000); | ||
}; | ||
|
||
if (!payloadEventResult) { | ||
return; | ||
} | ||
|
||
switch (payloadEventResult.event) { | ||
case "list": | ||
this.veadotubeStates = payloadEventResult.states; | ||
for (const state of this.veadotubeStates) { | ||
this.callStateThumb(state.id); | ||
} | ||
this.dispatchEvent(new StatesChangedEvent()); | ||
break; | ||
case "peek": | ||
// NOTE: do something with peek event ? | ||
break; | ||
case "thumb": | ||
this.veadotubeStates = this.veadotubeStates.map((state) => { | ||
if (state.id === payloadEventResult.stateId) { | ||
return { | ||
...state, | ||
image: { | ||
width: payloadEventResult.width, | ||
height: payloadEventResult.height, | ||
data: payloadEventResult.png | ||
} | ||
} | ||
} | ||
return state; | ||
}) | ||
this.dispatchEvent(new StatesChangedEvent()); | ||
break; | ||
} | ||
stopTimeoutTimer = () => { | ||
if (this.timeoutTimerId) { | ||
clearTimeout(this.timeoutTimerId); | ||
this.timeoutTimerId = null; | ||
} | ||
}; | ||
|
||
open = (initializeWithListStates:boolean = true) => { | ||
try { | ||
this.innerOpen(initializeWithListStates); | ||
} catch (e) { | ||
this.reset(); | ||
|
||
if (this.config.onErrorCallback) { | ||
this.config.onErrorCallback(WebsocketConnectingError); | ||
} else { | ||
console.error("failed to open websocket connection", e); | ||
} | ||
} | ||
} | ||
|
||
innerOpen = (initializeWithListStates:boolean) => { | ||
this.startTimeoutTimer(); | ||
const ws = new WebSocket(`ws://${this.config.host}:${this.config.port}?n=${this.config.clientName}`); | ||
console.debug("opening websocket connection to", this.config.host, this.config.port); | ||
|
||
ws.addEventListener("message", this.onMessage) | ||
|
||
ws.addEventListener("open", () => { | ||
this.stopTimeoutTimer(); | ||
if (initializeWithListStates) { | ||
this.listStates(); | ||
} | ||
this.dispatchEvent(new WebsocketStatusChangedEvent()); | ||
}) | ||
|
||
ws.addEventListener("close", (e) => { | ||
if (this.config.onCloseCallback) { | ||
this.config.onCloseCallback(e); | ||
} | ||
|
||
this.reset(); | ||
this.dispatchEvent(new WebsocketStatusChangedEvent()); | ||
}) | ||
|
||
ws.addEventListener("error", (e) => { | ||
this.reset(); | ||
|
||
if (this.config.onErrorCallback) { | ||
this.config.onErrorCallback(WebsocketError); | ||
} else { | ||
console.error("websocket error", e); | ||
} | ||
}) | ||
|
||
this.websocket = ws; | ||
this.dispatchEvent(new WebsocketStatusChangedEvent()); | ||
} | ||
|
||
close = () => { | ||
this.websocket?.close(); | ||
} | ||
|
||
sendRaw = (message: string) => { | ||
this.startTimeoutTimer(); | ||
this.websocket?.send(message); | ||
} | ||
onMessage = (event: MessageEvent<string>) => { | ||
this.stopTimeoutTimer(); | ||
const payloadEventResult = parseReceivedPayload(event); | ||
|
||
setState = (stateId: string) => { | ||
this.currentStateId = stateId; | ||
this.dispatchEvent(new StateChangedEvent()); | ||
this.sendRaw(messages.SET_STATE(stateId)); | ||
if (!payloadEventResult) { | ||
return; | ||
} | ||
|
||
listStates = () => { | ||
this.sendRaw(messages.LIST_STATES()); | ||
} | ||
|
||
callStateThumb = (stateId: string) => { | ||
this.sendRaw(messages.CALL_STATE_THUMB({ id: stateId })); | ||
} | ||
|
||
getStates = () => { | ||
return this.veadotubeStates; | ||
} | ||
|
||
getCurrentStateId = () => { | ||
return this.currentStateId; | ||
} | ||
switch (payloadEventResult.event) { | ||
case "list": | ||
this.veadotubeStates = payloadEventResult.states; | ||
for (const state of this.veadotubeStates) { | ||
this.callStateThumb(state.id); | ||
} | ||
this.dispatchEvent("statesChanged"); | ||
break; | ||
case "peek": | ||
// NOTE: do something with peek event ? | ||
break; | ||
case "thumb": | ||
this.veadotubeStates = this.veadotubeStates.map((state) => { | ||
if (state.id === payloadEventResult.stateId) { | ||
return { | ||
...state, | ||
image: { | ||
width: payloadEventResult.width, | ||
height: payloadEventResult.height, | ||
data: payloadEventResult.png, | ||
}, | ||
}; | ||
} | ||
return state; | ||
}); | ||
this.dispatchEvent("statesChanged"); | ||
break; | ||
} | ||
}; | ||
|
||
open = (initializeWithListStates: boolean = true) => { | ||
try { | ||
this.innerOpen(initializeWithListStates); | ||
} catch (e) { | ||
this.reset(); | ||
|
||
if (this.config.onErrorCallback) { | ||
this.config.onErrorCallback(WebsocketConnectingError); | ||
} else { | ||
console.error("failed to open websocket connection", e); | ||
} | ||
} | ||
}; | ||
|
||
innerOpen = (initializeWithListStates: boolean) => { | ||
this.startTimeoutTimer(); | ||
const ws = new WebSocket( | ||
`ws://${this.config.host}:${this.config.port}?n=${this.config.clientName}` | ||
); | ||
console.debug( | ||
"opening websocket connection to", | ||
this.config.host, | ||
this.config.port | ||
); | ||
|
||
ws.addEventListener("message", this.onMessage); | ||
|
||
ws.addEventListener("open", () => { | ||
this.stopTimeoutTimer(); | ||
if (initializeWithListStates) { | ||
this.listStates(); | ||
} | ||
this.dispatchEvent("websocketStatusChanged"); | ||
}); | ||
|
||
ws.addEventListener("close", (e) => { | ||
if (this.config.onCloseCallback) { | ||
this.config.onCloseCallback(e); | ||
} | ||
|
||
this.reset(); | ||
this.dispatchEvent("websocketStatusChanged"); | ||
}); | ||
|
||
ws.addEventListener("error", (e) => { | ||
this.reset(); | ||
|
||
if (this.config.onErrorCallback) { | ||
this.config.onErrorCallback(WebsocketError); | ||
} else { | ||
console.error("websocket error", e); | ||
} | ||
}); | ||
|
||
this.websocket = ws; | ||
this.dispatchEvent("websocketStatusChanged"); | ||
}; | ||
|
||
close = () => { | ||
this.websocket?.close(); | ||
}; | ||
|
||
sendRaw = (message: string) => { | ||
this.startTimeoutTimer(); | ||
this.websocket?.send(message); | ||
}; | ||
|
||
setState = (stateId: string) => { | ||
this.currentStateId = stateId; | ||
this.dispatchEvent("stateChanged"); | ||
this.sendRaw(messages.SET_STATE(stateId)); | ||
}; | ||
|
||
listStates = () => { | ||
this.sendRaw(messages.LIST_STATES()); | ||
}; | ||
|
||
callStateThumb = (stateId: string) => { | ||
this.sendRaw(messages.CALL_STATE_THUMB({ id: stateId })); | ||
}; | ||
|
||
getStates = () => { | ||
return this.veadotubeStates; | ||
}; | ||
|
||
getCurrentStateId = () => { | ||
return this.currentStateId; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters