2018-03-22 05:31:34 +01:00
|
|
|
import { Injectable } from "@angular/core";
|
2018-09-14 02:01:25 +02:00
|
|
|
import { BehaviorSubject } from "rxjs";
|
2019-03-01 04:54:26 +01:00
|
|
|
|
|
|
|
import { Status } from "./models/mastodon.interfaces";
|
2018-09-14 02:01:25 +02:00
|
|
|
import { ApiRoutes } from "./models/api.settings";
|
2018-11-03 19:12:14 +01:00
|
|
|
import { StreamTypeEnum, StreamElement } from "../states/streams.state";
|
2019-10-02 06:14:40 +02:00
|
|
|
import { MastodonWrapperService } from "./mastodon-wrapper.service";
|
2018-09-16 09:00:35 +02:00
|
|
|
import { AccountInfo } from "../states/accounts.state";
|
2019-10-04 02:05:27 +02:00
|
|
|
import { AccountIconComponent } from '../components/left-side-bar/account-icon/account-icon.component';
|
2018-03-22 05:31:34 +01:00
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
export class StreamingService {
|
2018-11-03 19:24:50 +01:00
|
|
|
|
2018-11-24 05:04:02 +01:00
|
|
|
public readonly nbStatusPerIteration: number = 20;
|
2018-11-03 19:24:50 +01:00
|
|
|
|
2018-09-16 09:00:35 +02:00
|
|
|
constructor(
|
2019-10-02 06:14:40 +02:00
|
|
|
private readonly mastodonService: MastodonWrapperService) { }
|
2018-03-22 05:31:34 +01:00
|
|
|
|
2018-11-03 19:12:14 +01:00
|
|
|
getStreaming(accountInfo: AccountInfo, stream: StreamElement): StreamingWrapper {
|
2019-09-12 06:08:28 +02:00
|
|
|
|
|
|
|
console.warn('EventSourceStreaminWrapper');
|
|
|
|
new EventSourceStreaminWrapper(accountInfo, stream);
|
|
|
|
|
2018-11-03 19:24:50 +01:00
|
|
|
return new StreamingWrapper(this.mastodonService, accountInfo, stream, this.nbStatusPerIteration);
|
2018-09-14 02:01:25 +02:00
|
|
|
}
|
2018-03-22 05:31:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export class StreamingWrapper {
|
2018-09-14 02:01:25 +02:00
|
|
|
statusUpdateSubjet = new BehaviorSubject<StatusUpdate>(null);
|
|
|
|
eventSource: WebSocket;
|
2018-09-16 09:00:35 +02:00
|
|
|
private apiRoutes = new ApiRoutes();
|
2018-11-24 05:04:02 +01:00
|
|
|
private errorClosing: boolean;
|
|
|
|
private since_id: string;
|
|
|
|
private disposed: boolean;
|
2018-03-22 05:31:34 +01:00
|
|
|
|
2018-09-16 09:00:35 +02:00
|
|
|
constructor(
|
2019-10-02 06:14:40 +02:00
|
|
|
private readonly mastodonService: MastodonWrapperService,
|
2018-11-03 19:12:14 +01:00
|
|
|
private readonly account: AccountInfo,
|
2018-11-03 19:24:50 +01:00
|
|
|
private readonly stream: StreamElement,
|
|
|
|
private readonly nbStatusPerIteration: number) {
|
2018-09-16 09:00:35 +02:00
|
|
|
|
2019-10-04 02:05:27 +02:00
|
|
|
this.start(account, stream);
|
2018-09-14 02:01:25 +02:00
|
|
|
}
|
2018-09-13 08:02:24 +02:00
|
|
|
|
2018-11-24 05:04:02 +01:00
|
|
|
dispose(): any {
|
|
|
|
this.disposed = true;
|
|
|
|
this.eventSource.close();
|
|
|
|
}
|
|
|
|
|
2019-10-04 02:05:27 +02:00
|
|
|
private start(account: AccountInfo, stream: StreamElement) {
|
|
|
|
this.mastodonService.refreshAccountIfNeeded(account)
|
|
|
|
.catch(err => {
|
|
|
|
return account;
|
|
|
|
})
|
|
|
|
.then((refreshedAccount: AccountInfo) => {
|
|
|
|
const route = this.getRoute(refreshedAccount, stream);
|
|
|
|
this.eventSource = new WebSocket(route);
|
|
|
|
this.eventSource.onmessage = x => {
|
|
|
|
if (x.data !== '') {
|
|
|
|
this.statusParsing(<WebSocketEvent>JSON.parse(x.data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.eventSource.onerror = x => this.webSocketGotError(x);
|
|
|
|
this.eventSource.onopen = x => { };
|
|
|
|
this.eventSource.onclose = x => this.webSocketClosed(refreshedAccount, stream, x);
|
|
|
|
});
|
2018-09-16 08:09:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private webSocketGotError(x: Event) {
|
|
|
|
this.errorClosing = true;
|
|
|
|
}
|
|
|
|
|
2019-10-04 02:05:27 +02:00
|
|
|
private webSocketClosed(account: AccountInfo, stream: StreamElement, x: Event) {
|
2018-09-16 09:00:35 +02:00
|
|
|
if (this.errorClosing) {
|
2019-07-04 06:36:43 +02:00
|
|
|
setTimeout(() => {
|
2019-10-04 02:05:27 +02:00
|
|
|
this.pullNewStatuses();
|
2019-07-04 06:36:43 +02:00
|
|
|
this.errorClosing = false;
|
|
|
|
}, 60 * 1000);
|
2018-11-24 05:04:02 +01:00
|
|
|
} else if (!this.disposed) {
|
2019-10-04 02:05:27 +02:00
|
|
|
setTimeout(() => { this.start(account, stream) }, 60 * 1000);
|
2018-11-02 04:49:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-04 02:05:27 +02:00
|
|
|
private pullNewStatuses() {
|
2019-05-19 02:44:36 +02:00
|
|
|
this.mastodonService.getTimeline(this.account, this.stream.type, null, this.since_id, this.nbStatusPerIteration, this.stream.tag, this.stream.listId)
|
2018-11-03 19:12:14 +01:00
|
|
|
.then((status: Status[]) => {
|
|
|
|
// status = status.sort((n1, n2) => { return (<number>n1.id) < (<number>n2.id); });
|
|
|
|
status = status.sort((a, b) => a.id.localeCompare(b.id));
|
|
|
|
for (const s of status) {
|
|
|
|
const update = new StatusUpdate();
|
|
|
|
update.status = s;
|
|
|
|
update.type = EventEnum.update;
|
|
|
|
this.since_id = update.status.id;
|
|
|
|
this.statusUpdateSubjet.next(update);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(err => {
|
|
|
|
console.error(err);
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
// setTimeout(() => { this.start(domain) }, 20 * 1000);
|
2018-11-24 05:04:02 +01:00
|
|
|
if (!this.disposed) {
|
2019-10-04 02:05:27 +02:00
|
|
|
setTimeout(() => { this.pullNewStatuses() }, 60 * 1000);
|
2018-11-24 05:04:02 +01:00
|
|
|
}
|
2018-11-03 19:12:14 +01:00
|
|
|
});
|
2018-09-14 02:01:25 +02:00
|
|
|
}
|
2018-09-13 08:02:24 +02:00
|
|
|
|
2018-09-16 08:09:48 +02:00
|
|
|
private statusParsing(event: WebSocketEvent) {
|
2018-09-14 02:01:25 +02:00
|
|
|
const newUpdate = new StatusUpdate();
|
|
|
|
|
|
|
|
switch (event.event) {
|
|
|
|
case 'update':
|
|
|
|
newUpdate.type = EventEnum.update;
|
|
|
|
newUpdate.status = <Status>JSON.parse(event.payload);
|
|
|
|
break;
|
|
|
|
case 'delete':
|
|
|
|
newUpdate.type = EventEnum.delete;
|
|
|
|
newUpdate.messageId = event.payload;
|
2019-07-06 04:27:40 +02:00
|
|
|
newUpdate.account = this.account;
|
2018-09-14 02:01:25 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
newUpdate.type = EventEnum.unknow;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.statusUpdateSubjet.next(newUpdate);
|
|
|
|
}
|
2018-09-16 08:09:48 +02:00
|
|
|
|
2018-11-03 19:12:14 +01:00
|
|
|
private getRoute(account: AccountInfo, stream: StreamElement): string {
|
|
|
|
const streamingRouteType = this.getStreamingRouteType(stream.type);
|
|
|
|
let route = `wss://${account.instance}${this.apiRoutes.getStreaming}`.replace('{0}', account.token.access_token).replace('{1}', streamingRouteType);
|
|
|
|
|
2018-11-24 05:04:02 +01:00
|
|
|
if (stream.tag) route = `${route}&tag=${stream.tag}`;
|
2019-05-19 02:44:36 +02:00
|
|
|
if (stream.list) route = `${route}&list=${stream.listId}`;
|
2018-11-03 19:12:14 +01:00
|
|
|
|
|
|
|
return route;
|
|
|
|
}
|
|
|
|
|
|
|
|
private getStreamingRouteType(type: StreamTypeEnum): string {
|
2018-09-16 09:00:35 +02:00
|
|
|
switch (type) {
|
|
|
|
case StreamTypeEnum.global:
|
|
|
|
return 'public';
|
|
|
|
case StreamTypeEnum.local:
|
|
|
|
return 'public:local';
|
|
|
|
case StreamTypeEnum.personnal:
|
|
|
|
return 'user';
|
2018-11-03 19:12:14 +01:00
|
|
|
case StreamTypeEnum.directmessages:
|
|
|
|
return 'direct';
|
|
|
|
case StreamTypeEnum.tag:
|
|
|
|
return 'hashtag';
|
|
|
|
case StreamTypeEnum.list:
|
|
|
|
return 'list';
|
|
|
|
default:
|
|
|
|
throw Error('Not supported');
|
2018-09-16 09:00:35 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-13 08:02:24 +02:00
|
|
|
}
|
|
|
|
|
2019-09-12 06:08:28 +02:00
|
|
|
export class EventSourceStreaminWrapper {
|
|
|
|
eventSource: EventSource;
|
|
|
|
private apiRoutes = new ApiRoutes();
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
private readonly account: AccountInfo,
|
|
|
|
private readonly stream: StreamElement
|
|
|
|
){
|
|
|
|
this.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
private start(){
|
|
|
|
const route = this.getRoute();
|
|
|
|
this.eventSource = new EventSource(route);
|
|
|
|
this.eventSource.addEventListener('update', u => {
|
|
|
|
console.warn('update');
|
|
|
|
console.warn(u);
|
|
|
|
});
|
|
|
|
this.eventSource.addEventListener('delete', d => {
|
|
|
|
console.warn('delete');
|
|
|
|
console.warn(d);
|
|
|
|
});
|
|
|
|
this.eventSource.onmessage = x => {
|
|
|
|
console.log(x);
|
|
|
|
if(x.data !== ''){
|
|
|
|
this.onMessage(JSON.parse(x.data));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
this.eventSource.onerror = x => {
|
|
|
|
this.onError(x);
|
|
|
|
};
|
|
|
|
|
|
|
|
console.warn('this.eventSource.CONNECTING');
|
|
|
|
console.warn(this.eventSource.CONNECTING);
|
|
|
|
console.warn('this.eventSource.OPEN');
|
|
|
|
console.warn(this.eventSource.OPEN);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
private onMessage(data) {
|
|
|
|
console.warn('onMessage');
|
|
|
|
console.warn(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
private onError(data) {
|
|
|
|
console.warn('onError');
|
|
|
|
console.warn(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
private getRoute(): string {
|
|
|
|
const streamingRouteType = this.getStreamingRouteType(this.stream.type);
|
|
|
|
let route = `https://${this.account.instance}/api/v1/streaming/${streamingRouteType}?access_token=${this.account.token.access_token}`;
|
|
|
|
return route;
|
|
|
|
}
|
|
|
|
|
|
|
|
private getStreamingRouteType(type: StreamTypeEnum): string {
|
|
|
|
switch (type) {
|
|
|
|
case StreamTypeEnum.global:
|
|
|
|
return 'public';
|
|
|
|
case StreamTypeEnum.local:
|
|
|
|
return 'public/local';
|
|
|
|
case StreamTypeEnum.personnal:
|
|
|
|
return 'user';
|
|
|
|
case StreamTypeEnum.directmessages:
|
|
|
|
return 'direct';
|
|
|
|
case StreamTypeEnum.tag:
|
|
|
|
return 'hashtag?tag={0}';
|
|
|
|
case StreamTypeEnum.list:
|
|
|
|
return 'list?list={0}';
|
|
|
|
case StreamTypeEnum.directmessages:
|
|
|
|
return 'direct';
|
|
|
|
default:
|
|
|
|
throw Error('Not supported');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-13 08:02:24 +02:00
|
|
|
class WebSocketEvent {
|
2018-09-14 02:01:25 +02:00
|
|
|
event: string;
|
|
|
|
payload: any;
|
2018-09-13 08:02:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export class StatusUpdate {
|
2018-09-14 02:01:25 +02:00
|
|
|
type: EventEnum;
|
|
|
|
status: Status;
|
2019-07-06 04:27:40 +02:00
|
|
|
messageId: string;
|
|
|
|
account: AccountInfo;
|
2018-09-13 08:02:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export enum EventEnum {
|
2018-09-14 02:01:25 +02:00
|
|
|
unknow = 0,
|
|
|
|
update = 1,
|
|
|
|
delete = 2
|
2018-03-22 05:31:34 +01:00
|
|
|
}
|