Skip to content

Instantly share code, notes, and snippets.

@joekiller
Created April 23, 2022 15:13
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joekiller/f513e9279c1291d76d1edbf7386f9796 to your computer and use it in GitHub Desktop.
Save joekiller/f513e9279c1291d76d1edbf7386f9796 to your computer and use it in GitHub Desktop.
BackpackSocketManager

Dependencies:

npm install --save-dev @types/ws
npm install reconnecting-websocket ws
import ReconnectingWebSocket from 'reconnecting-websocket';
import WS from 'ws';
import * as Events from 'reconnecting-websocket/events';
export default class BackpackSocketManager {
private ws: ReconnectingWebSocket;
constructor() {
this.ws = new ReconnectingWebSocket('wss://ws.backpack.tf/events', [], {
WebSocket: WS,
maxEnqueuedMessages: 0,
startClosed: true
})
this.ws.addEventListener('open', this.socketConnect());
this.ws.addEventListener('error', err => {
console.log(err);
});
this.ws.addEventListener('close', this.socketDisconnected());
}
private socketDisconnected() {
return () => {
console.debug('Disconnected from socket server');
};
}
private socketConnect() {
return () => {
console.debug('Connected to socket server');
};
}
connect(): void {
this.ws.reconnect();
}
on<T extends keyof Events.WebSocketEventListenerMap>(name: T, handler: Events.WebSocketEventListenerMap[T]): void {
this.ws.addEventListener(name, handler);
}
}
import BackpackSocketManager from "./BackpackSocketManager";
export interface UserAgent {
client: string;
lastPulse: number;
}
export interface User {
id: string;
name: string;
avatar: string;
avatarFull: string;
premium: boolean;
online: boolean;
banned: boolean;
customNameStyle: string;
acceptedSuggestions: number;
class: string;
style: string;
tradeOfferUrl: string;
isMarketplaceSeller: boolean;
flagImpersonated?: any;
bans: any[];
}
export interface Currencies {
metal?: number;
keys?: number;
usd?: number;
}
export interface KillEater2 {
name: string;
}
export interface KillEater {
score: number;
killEater: KillEater2;
}
export interface Origin {
id: number;
name: string;
}
export interface Steam {
currency: string;
short: string;
long: string;
raw: number;
value: number;
}
export interface Metadata {
appid: number;
quality: number;
defindexes: number[];
item_name: string;
base_item_name: string;
priceindex: string;
tradable: boolean;
craftable: boolean;
value_raw: number;
used_by_classes: string[];
item_slot: string;
release_date: number;
}
export interface Community {
metadata: Metadata;
value: number;
valueHigh: number;
currency: string;
raw: number;
short: string;
long: string;
updatedAt: number;
difference: number;
}
export interface Suggested {
raw: number;
short: string;
long: string;
}
export interface Price {
steam: Steam;
community: Community;
suggested: Suggested;
}
export interface Quality {
id: number;
name: string;
color: string;
}
export interface Summary {
value: string;
}
export interface Spell {
id: string;
spellId: string;
name: string;
type: string;
defindex?: number;
color?: string;
}
interface Particle {
"id": number;
"name": string;
"shortName": string;
"imageUrl": string;
"type": string;
}
interface MpListing {
"value": number,
"raw": number,
"short": string,
"currency": string
}
export interface Item {
appid: number;
australium: boolean;
baseName: string;
class: string[];
craftable: boolean;
defindex: number;
festivized: boolean;
id: string;
imageUrl: string;
killEaters?: KillEater[];
level: number;
marketName: string;
name: string;
origin: Origin;
originalId: string;
particle?: Particle;
priceindex: string;
price: Price;
quality: Quality;
quantity: number;
slot: string;
tradable: boolean;
summary: Summary;
spells?: Spell[];
marketplaceTfListing?: MpListing;
}
export interface Spell {
id: string;
spellId: string;
name: string;
type: string;
defindex?: number;
color?: string;
}
interface Particle {
"id": number;
"name": string;
"shortName": string;
"imageUrl": string;
"type": string;
}
interface MpListing {
"value": number,
"raw": number,
"short": string,
"currency": string
}
export interface Item {
appid: number;
australium: boolean;
baseName: string;
class: string[];
craftable: boolean;
defindex: number;
festivized: boolean;
id: string;
imageUrl: string;
killEaters?: KillEater[];
level: number;
marketName: string;
name: string;
origin: Origin;
originalId: string;
particle?: Particle;
priceindex: string;
price: Price;
quality: Quality;
quantity: number;
slot: string;
tradable: boolean;
summary: Summary;
spells?: Spell[];
marketplaceTfListing?: MpListing;
}
export interface Value {
raw: number;
short: string;
long: string;
}
export interface Listing {
id: string;
steamid: string;
appid: number;
currencies: Currencies;
value: Value;
tradeOffersPreferred: boolean;
buyoutOnly: boolean;
details?: string | null | undefined;
listedAt: number;
bumpedAt: number;
intent: string;
item: Item;
count: number;
status: string;
userAgent?: UserAgent;
user: User;
}
let notifications: string[] = [];
const backpackSocket = new BackpackSocketManager();
backpackSocket.on('message', (m) => {
if(typeof m.data === 'string') {
notifications.push(m.data);
} else {
console.error(`cannot add ${m}`);
}
});
backpackSocket.connect();
getListings = (): { event: string, payload: Listing }[] => {
const lastIndex = notifications.length;
const copy = notifications.slice(0,lastIndex);
notifications = notifications.slice(lastIndex);
return copy.map(e => JSON.parse(e));
};
while(true) {
const listings = getListings();
console.log(JSON.stringify(listings, null, 2));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment