This commit is contained in:
Robin Appelman 2020-05-08 19:36:04 +02:00
commit cc607167ec
12 changed files with 3625 additions and 4351 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,22 +0,0 @@
// declare module 'steam-user' {
// export * from "steam-user-enums";
//
// export interface ILoginParams {
// accountName: string;
// password: string;
// }
//
// export class Chat {
//
// }
//
// export default class SteamUser {
// constructor();
//
// public logOn(params: any): void;
//
// public on(hook: string, callback: any): void;
// }
// }
//
//

View file

@ -1,54 +0,0 @@
declare module 'steam-user-interfaces' {
import {EChatEntryType, EChatRoomServerMessage} from "steam-user-enums";
import SteamId from "steamid";
export interface IIncomingFriendMessage {
steamid_friend: SteamId,
chat_entry_type: EChatEntryType,
from_limited_account: boolean,
message: string,
message_no_bbcode: string,
server_timestamp: Date,
ordinal: number,
local_echo: boolean,
low_priority: boolean
}
export interface IIncomingChatMessage {
chat_group_id: string,
chat_id: string,
steamid_sender: SteamId,
chat_entry_type: EChatEntryType,
from_limited_account: boolean,
message: string,
message_no_bbcode: string,
server_timestamp: Date,
ordinal: number,
mentions: IChatMentions | null,
}
export interface IChatMentions {
mention_all: boolean,
mention_here,
mention_steamids: SteamId[]
}
export interface IServerMessage {
message: EChatRoomServerMessage,
string_param?: string,
steamid_param?: SteamId
}
// incomplete
export interface IPersona {
player_name: string,
avatar_hash: Buffer,
last_logoff: Date,
last_logon: Date,
last_seen_online: Date,
game_name: string,
avatar_url_icon: string,
avatar_url_medium: string,
avatar_url_full: string
}
}

3421
src/enum.ts Normal file

File diff suppressed because it is too large Load diff

View file

@ -7,15 +7,11 @@ import {
} from "mx-puppet-bridge";
import * as commandLineArgs from "command-line-args";
import * as commandLineUsage from "command-line-usage";
import * as escapeHtml from "escape-html";
import {Steam} from "./steam";
import {NextcloudConfigWrap} from "./config";
import * as fs from "fs";
import * as yaml from "js-yaml";
import {GetDataFromStrHook, IPuppetData} from "mx-puppet-bridge/lib/src";
import * as SteamCommunity from 'steamcommunity';
import {LoginDetails, LoginToken} from "./login";
import * as SteamID from "steamid";
import * as SteamUser from "steam-user";
const log = new Log("NextcloudPuppet:index");
@ -49,7 +45,7 @@ if (options.help) {
}
const protocol = {
features: {typingTimeout : 1 * 1000},
features: {typingTimeout : 1000, presence: true},
id: "steam",
displayname: "Steam",
externalUrl: "https://steamcommunity.com/",

77
src/interfaces.ts Normal file
View file

@ -0,0 +1,77 @@
import SteamId from "steamid";
import {EPersonaState, EChatEntryType, EChatRoomServerMessage} from "./enum";
export interface IIncomingFriendMessage {
steamid_friend: SteamId,
chat_entry_type: EChatEntryType,
from_limited_account: boolean,
message: string,
message_no_bbcode: string,
server_timestamp: Date,
ordinal: number,
local_echo: boolean,
low_priority: boolean
}
export interface IIncomingChatMessage {
chat_group_id: string,
chat_id: string,
steamid_sender: SteamId,
chat_entry_type: EChatEntryType,
from_limited_account: boolean,
message: string,
message_no_bbcode: string,
server_timestamp: Date,
ordinal: number,
mentions: IChatMentions | null,
}
export interface IChatMentions {
mention_all: boolean,
mention_here,
mention_steamids: SteamId[]
}
export interface IServerMessage {
message: EChatRoomServerMessage,
string_param?: string,
steamid_param?: SteamId
}
// incomplete
export interface IPersona {
persona_state: EPersonaState,
player_name: string,
avatar_hash: Buffer,
last_logoff: Date,
last_logon: Date,
last_seen_online: Date,
game_name: string,
gameid: string,
avatar_url_icon: string,
avatar_url_medium: string,
avatar_url_full: string
}
export interface AppInfo {
changenumber: number,
missingToken: boolean,
appinfo: {
appid: string,
common: {
name: string,
type: string,
releasestate: string,
oslist: string,
logo: string,
logo_small: string,
icon: string,
},
extended: {
developer: string,
publisher: string,
homepage: string,
listofdlc: string
}
}
}

View file

@ -1,20 +1,17 @@
/// <reference path="@types/steam-user/enum.d.ts" />
/// <reference path="@types/steam-user/interfaces.d.ts" />
import {
PuppetBridge,
Log,
IFileEvent,
IMessageEvent,
IReceiveParams,
IRemoteRoom,
IRemoteUser,
IMessageEvent,
IFileEvent,
Util,
IRetList,
Log,
PuppetBridge,
} from "mx-puppet-bridge";
import * as SteamUser from "steam-user";
import * as SteamID from "steamid";
import {IIncomingFriendMessage, IPersona} from "steam-user-interfaces";
import {EPersonaState} from "./enum";
import {MatrixPresence} from "mx-puppet-bridge/lib/src/presencehandler";
import {AppInfo, IIncomingFriendMessage, IPersona} from "./interfaces";
const log = new Log("MatrixPuppet:Steam");
@ -23,6 +20,7 @@ interface ISteamPuppet {
data: any;
sentEventIds: string[];
knownPersonas: Map<string, IPersona>,
knownApps: Map<string, AppInfo>,
}
interface ISteamPuppets {
@ -32,6 +30,7 @@ interface ISteamPuppets {
interface IPuppetParams {
accountName: string,
loginKey: string,
[key: string]: string;
}
@ -46,7 +45,7 @@ export class Steam {
async getPersona(p: ISteamPuppet, steamid: SteamID): Promise<IPersona> {
let steamIdString = steamid.toString();
let persona = p.knownPersonas.get(steamIdString)
let persona = p.knownPersonas.get(steamIdString);
if (persona) {
return persona;
} else if (p.client.users[steamIdString]) {
@ -59,6 +58,18 @@ export class Steam {
}
}
async getProduct(p: ISteamPuppet, appId: string): Promise<AppInfo> {
let app = p.knownApps.get(appId);
if (app) {
return app;
} else {
let {apps} = await p.client.getProductInfo([parseInt(appId, 10)], []);
let app = apps[appId];
p.knownApps.set(appId, app);
return app;
}
}
public async getSendParams(puppetId: number, msg: IIncomingFriendMessage, fromSteamId?: SteamID): Promise<IReceiveParams> {
const p = this.puppets[puppetId];
@ -93,6 +104,7 @@ export class Steam {
sentEventIds: [],
typingUsers: {},
knownPersonas: new Map(),
knownApps: new Map(),
} as ISteamPuppet;
try {
client.logOn({
@ -101,18 +113,57 @@ export class Steam {
rememberPassword: true,
});
client.on("user", (steamId, persona) => {
this.puppets[puppetId].knownPersonas.set(steamId.toString(), persona);
client.on("user", async (steamId, persona: IPersona) => {
const p = this.puppets[puppetId];
p.knownPersonas.set(steamId.toString(), persona);
let state: MatrixPresence = "offline";
switch (persona.persona_state) {
case EPersonaState.Away:
case EPersonaState.Busy:
case EPersonaState.Snooze:
state = "unavailable";
break;
case EPersonaState.LookingToPlay:
case EPersonaState.LookingToTrade:
case EPersonaState.Online:
state = "online";
break;
}
if (steamId.toString() != client.steamID.toString()) {
await this.bridge.setUserPresence({
puppetId,
userId: steamId.toString()
}, state);
if (persona.gameid && persona.gameid !== '0') {
let app = await this.getProduct(p, persona.gameid);
await this.bridge.setUserStatus({
puppetId,
userId: steamId.toString()
}, `Now playing: ${app.appinfo.common.name}`);
} else {
await this.bridge.setUserStatus({
puppetId,
userId: steamId.toString()
}, "");
}
}
});
client.on("loggedOn", async (details) => {
await this.bridge.setUserId(puppetId, client.steamID.toString());
await this.bridge.sendStatusMessage(puppetId, `connected as ${details.vanity_url}(${client.steamID.toString()})!`);
})
client.setPersona(EPersonaState.Away);
});
client.on("loginKey", (loginKey) => {
console.log("got new login key");
log.info("got new login key");
data.loginKey = loginKey;
this.bridge.setPuppetData(puppetId, data);
});
@ -125,7 +176,7 @@ export class Steam {
});
client.chat.on("friendTyping", (message: IIncomingFriendMessage) => {
this.handleFriendTyping(puppetId, message);
})
});
client.on("error", (err) => {
log.error(`Failed to start up puppet ${puppetId}`, err);
@ -171,7 +222,6 @@ export class Steam {
}, true);
}
public async sendMessageToSteam(
p: ISteamPuppet,
room: IRemoteRoom,
@ -179,22 +229,20 @@ export class Steam {
msg: string,
mediaId?: string,
) {
let id = "";
try {
let _roomSteamId = new SteamID(room.name as string);
let _roomSteamId = new SteamID(room.roomId as string);
if (_roomSteamId.isValid()) {
const sendMessage = await p.client.chat.sendFriendMessage(room.roomId, msg);
id = `${sendMessage.server_timestamp.toISOString()}::${sendMessage.ordinal}`;
let id = `${sendMessage.server_timestamp.toISOString()}::${sendMessage.ordinal}`;
await this.bridge.eventSync.insert(room, eventId, id);
p.sentEventIds.push(id);
} else {
await this.bridge.sendStatusMessage(room.puppetId, `Sending group messages is currently not supported`);
}
} catch (e) {
await this.bridge.sendStatusMessage(room.puppetId, `Sending group messages is currently not supported`);
}
await this.bridge.eventSync.insert(room, eventId, id);
p.sentEventIds.push(id);
}
public async handleMatrixMessage(room: IRemoteRoom, data: IMessageEvent, event: any) {
@ -228,11 +276,15 @@ export class Steam {
if (!p) {
return null;
}
let persona = await this.getPersona(p, new SteamID(user.userId));
log.info(`Got request to create user ${user.userId}`);
return {
userId: user.userId,
puppetId: user.puppetId,
name: user.name,
name: persona.player_name,
avatarUrl: persona.avatar_url_medium
};
}