Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/environment.dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export const environment = {
ws: 'wss://notary.csfloat.com/proxy',
loggingLevel: 'Error',
},
reverse_watch_base_api_url: 'http://localhost:3434/api',
};
1 change: 1 addition & 0 deletions src/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export const environment = {
ws: 'wss://notary.csfloat.com/proxy',
loggingLevel: 'Warn',
},
reverse_watch_base_api_url: 'https://reverse.watch/api',
};
31 changes: 31 additions & 0 deletions src/lib/bridge/handlers/fetch_reversal_status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {RequestType} from './types';
import {SimpleHandler} from './main';
import {environment} from '../../../environment';

export interface FetchReversalStatusRequest {
steam_id64: string;
}

export interface FetchReversalStatusResponse {
steam_id: string;
has_reversed: boolean;
last_reversal_timestamp?: number;
}

export interface FetchReversalStatusError {
code: string;
message: string;
details?: string;
}

export const FetchReversalStatus = new SimpleHandler<FetchReversalStatusRequest, FetchReversalStatusResponse>(
RequestType.FETCH_REVERSAL_STATUS,
async (req) => {
const resp = await fetch(`${environment.reverse_watch_base_api_url}/v1/users/${req.steam_id64}`);
const data = (await resp.json()) as FetchReversalStatusResponse | FetchReversalStatusError;
if (!resp.ok) {
throw Error((data as FetchReversalStatusError).message ?? 'unknown error');
}
return data as FetchReversalStatusResponse;
}
);
2 changes: 2 additions & 0 deletions src/lib/bridge/handlers/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {NotaryProve} from './notary_prove';
import {FetchNotaryMeta} from './fetch_notary_meta';
import {FetchNotaryToken} from './fetch_notary_token';
import {FetchSteamPoweredInventory} from './fetch_steam_inventory';
import {FetchReversalStatus} from './fetch_reversal_status';

export const HANDLERS_MAP: {[key in RequestType]: RequestHandler<any, any>} = {
[RequestType.EXECUTE_SCRIPT_ON_PAGE]: ExecuteScriptOnPage,
Expand Down Expand Up @@ -76,4 +77,5 @@ export const HANDLERS_MAP: {[key in RequestType]: RequestHandler<any, any>} = {
[RequestType.FETCH_NOTARY_META]: FetchNotaryMeta,
[RequestType.FETCH_NOTARY_TOKEN]: FetchNotaryToken,
[RequestType.FETCH_STEAM_POWERED_INVENTORY]: FetchSteamPoweredInventory,
[RequestType.FETCH_REVERSAL_STATUS]: FetchReversalStatus,
};
1 change: 1 addition & 0 deletions src/lib/bridge/handlers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ export enum RequestType {
FETCH_NOTARY_META = 34,
FETCH_NOTARY_TOKEN = 35,
FETCH_STEAM_POWERED_INVENTORY = 36,
FETCH_REVERSAL_STATUS = 37,
}
132 changes: 132 additions & 0 deletions src/lib/components/profile/reversal_status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import {CustomElement, InjectAfter, InjectionMode} from '../injectors';
import {FloatElement} from '../custom';
import {css, html} from 'lit';
import {state} from 'lit/decorators.js';
import {FetchReversalStatusResponse} from '../../bridge/handlers/fetch_reversal_status';
import {gReversalFetcher} from '../../services/reversal_fetcher';
import {defined} from '../../utils/checkers';

@CustomElement()
@InjectAfter(
'.profile_in_game.persona + .profile_ban_status, .profile_in_game.persona:not(:has(+ .profile_ban_status))',
InjectionMode.ONCE
)
export class ReversalStatus extends FloatElement {
@state()
reversalStatus: FetchReversalStatusResponse | undefined = undefined;

static styles = [
...FloatElement.styles,
css`
.container {
display: flex;
align-items: center;
gap: 6px;
color: #de6667;
margin-bottom: 10px;

.warning {
display: inline;

.info-link-container {
color: #828282;

.info-link {
text-decoration: none;
color: #ebebeb;

&:hover {
color: #66c0f4;
}
}
}

.powered-by-container {
font-size: 12px;
color: #828282;

.powered-by-link {
text-decoration: none;
color: #ebebeb;

&:hover {
color: #66c0f4;
}
}
}
}
}
`,
];

get show(): boolean {
return !!this.reversalStatus?.has_reversed;
}

get daysSinceLastReversal(): number | null {
if (!this.reversalStatus?.last_reversal_timestamp) {
return null;
}

const now = Date.now();
const timeSince = now - this.reversalStatus.last_reversal_timestamp;
return Math.floor(timeSince / (24 * 60 * 60 * 1000));
}

getSteamId(): string | undefined {
if (defined(typeof g_rgProfileData) && g_rgProfileData) {
return g_rgProfileData.steamid;
}

const match = window.location.pathname.match(/^\/profiles\/(\d+)/);
if (match) {
return match[1];
}
}

async connectedCallback() {
super.connectedCallback();

try {
const steamId = this.getSteamId();
if (!steamId) {
console.error('failed to get steam id');
return;
}

this.reversalStatus = await gReversalFetcher.fetch({steam_id64: steamId});
} catch (e) {
console.error('failed to fetch reversal status', e);
}
}

protected render() {
if (!this.show) {
return html``;
}

const daysSince = this.daysSinceLastReversal ?? 0;
const message = `${daysSince} day(s) since last trade reversal`;
return html`
<div class="container">
<div class="warning">
${message}
<span class="info-link-container">
|
<a
class="info-link"
href="https://help.steampowered.com/en/faqs/view/365F-4BEE-2AE2-7BDD"
target="_blank"
rel="noreferrer"
>
Info
</a>
</span>
<span class="powered-by-container"
>(powered by <a class="powered-by-link" href="https://reverse.watch">reverse.watch</a>)</span
>
</div>
</div>
`;
}
}
1 change: 1 addition & 0 deletions src/lib/page_scripts/profile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {init} from './utils';
import '../components/profile/comment_warning';
import '../components/profile/reversal_status';

init('src/lib/page_scripts/profile.js', main);

Expand Down
33 changes: 33 additions & 0 deletions src/lib/services/reversal_fetcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {ClientSend} from '../bridge/client';
import {
FetchReversalStatus,
FetchReversalStatusRequest,
FetchReversalStatusResponse,
} from '../bridge/handlers/fetch_reversal_status';
import {GenericJob, TTLCachedQueue} from '../utils/queue';

class ReversalFetcher extends TTLCachedQueue<FetchReversalStatusRequest, FetchReversalStatusResponse> {
constructor(maxConcurrency: number, ttlMs: number) {
super(maxConcurrency, ttlMs);
}

fetch(req: FetchReversalStatusRequest): Promise<FetchReversalStatusResponse> {
return this.add(new GenericJob(req));
}

protected async process(req: FetchReversalStatusRequest): Promise<FetchReversalStatusResponse> {
try {
return await ClientSend(FetchReversalStatus, req);
} catch (e) {
console.error('failed to fetch reversal status', e);
// Stub out to prevent future calls
return {
steam_id: '',
has_reversed: false,
last_reversal_timestamp: undefined,
} as FetchReversalStatusResponse;
}
}
}

export const gReversalFetcher = new ReversalFetcher(1, 30 * 60 * 1000 /* 30 minutes */);
9 changes: 9 additions & 0 deletions src/lib/types/steam.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,21 @@ export type SteamAssets = {
};
};

// g_rgProfileData
export interface ProfileData {
url: string;
steamid: string;
personaname: string;
summary?: string;
}

// Declares globals available in the Steam Page Context
declare global {
const $J: typeof $;
const g_rgListingInfo: {[listingId: string]: ListingData};
const g_rgWalletInfo: WalletInfo | undefined; // Not populated when user is signed-out
const g_rgAssets: SteamAssets;
const g_rgProfileData: ProfileData | undefined; // Only populated on Steam profile pages
const g_ActiveInventory: CAppwideInventory | CInventory | undefined; // Only populated on Steam inventory pages
const g_steamID: string;
const g_oSearchResults: CAjaxPagingControls;
Expand Down
Loading