+++ /dev/null
-import { TestBed } from '@angular/core/testing';
-
-import { ChatroomService } from './chatroom.service';
-
-describe('ChatroomService', () => {
- let service: ChatroomService;
-
- beforeEach(() => {
- TestBed.configureTestingModule({});
- service = TestBed.inject(ChatroomService);
- });
-
- it('should be created', () => {
- expect(service).toBeTruthy();
- });
-});
+++ /dev/null
-import { Injectable } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
-import { EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source';
-import { Observable, Subscriber } from 'rxjs';
-import { Chatroom } from './chatroom';
-import { Message } from './message';
-
-class RetriableError extends Error { }
-class CanceledError extends Error { }
-class FatalError extends Error { }
-
-@Injectable({
- providedIn: 'root'
-})
-export class ChatroomService {
-
- private backendUri = 'http://localhost:8080/';
-
- private channel: Subscriber<Message> = new Subscriber<Message>();
- private uri: string = "CLOSED";
- private canceled: boolean = false;
-
- constructor(private http: HttpClient) { }
-
- getChatrooms(): Observable<Chatroom[]> {
- return this.http.get<Chatroom[]>(this.backendUri + 'list');
- }
-
- getChatroom(shard: string, id: string): Observable<Chatroom> {
- return this.http.get<Chatroom>(
- this.backendUri + id,
- { headers: { 'X-Shard': shard }});
- }
-
- listen(shard: string, id: string): Observable<Message> {
- let observable = new Observable<Message>(
- (observer) => {
- this.channel = observer;
- });
-
- if (this.uri !== 'CLOSED') {
- console.log('Channel is still open, uncanceling ' + this.uri);
- this.canceled = false;
- return observable;
- }
-
- let uri: string = this.backendUri + id + '/listen';
- let service = this;
-
- fetchEventSource(uri,{
- headers: { 'X-Shard': shard },
- async onopen(response) {
- if (response.ok && response.status === 200) {
- console.log('Opend channel ' + uri, response);
- service.uri = uri;
- service.canceled = false;
- }
- else if (
- response.status >= 400 &&
- response.status < 500 &&
- response.status !== 429
- ) {
- console.error('Client side error when connecting to channel ' + uri, response);
- throw new FatalError();
- }
- },
- onmessage(event) {
- console.debug('Received message on channel: ' + uri);
- if (service.canceled)
- throw new CanceledError();
- service.processEvent(event);
- },
- onclose() {
- console.log('Server closed channel ' + uri);
- service.uri = "CLOSED";
- throw new RetriableError();
- },
- onerror(error) {
- console.log('Error on channel ' + uri, error);
- if (error instanceof CanceledError || error instanceof FatalError) {
- service.uri = "CLOSED";
- throw error; // rethrow to stop the operation
- }
- else {
- return 1000; // retry-intervall in ms
- }
- },
- openWhenHidden: true
- }).then(() => console.debug('Promise fullfilled for ' + uri));
-
- return observable;
- }
-
- unlisten(): void {
- console.log('Canceling channel ' + this.uri);
- this.canceled = true;
- }
-
- // Processes custom event types
- private processEvent(message: EventSourceMessage): void {
- const parsed = message.data ? JSON.parse(message.data) : {};
- switch (message.event) {
- case 'message': {
- this.channel.next(parsed);
- break;
- }
- case 'error': {
- // Not implemented server-side yet
- console.error('Received error-message from server on channel ' + this.uri, message.data);
- throw new FatalError(message.data);
- }
- // Add others if neccessary
- default: {
- console.error('Unhandled event:', message.event);
- break;
- }
- }
- }
-}
+++ /dev/null
-export interface Chatroom
-{
- id: string,
- name: string,
- shard: number
-}
--- /dev/null
+import { TestBed } from '@angular/core/testing';
+
+import { ChatroomService } from './chatroom.service';
+
+describe('ChatroomService', () => {
+ let service: ChatroomService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(ChatroomService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
--- /dev/null
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { EventSourceMessage, fetchEventSource } from '@microsoft/fetch-event-source';
+import { Observable, Subscriber } from 'rxjs';
+import { Chatroom } from './chatroom';
+import { Message } from './message';
+
+class RetriableError extends Error { }
+class CanceledError extends Error { }
+class FatalError extends Error { }
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ChatroomService {
+
+ private backendUri = 'http://localhost:8080/';
+
+ private channel: Subscriber<Message> = new Subscriber<Message>();
+ private uri: string = "CLOSED";
+ private canceled: boolean = false;
+
+ constructor(private http: HttpClient) { }
+
+ getChatrooms(): Observable<Chatroom[]> {
+ return this.http.get<Chatroom[]>(this.backendUri + 'list');
+ }
+
+ getChatroom(shard: string, id: string): Observable<Chatroom> {
+ return this.http.get<Chatroom>(
+ this.backendUri + id,
+ { headers: { 'X-Shard': shard }});
+ }
+
+ listen(shard: string, id: string): Observable<Message> {
+ let observable = new Observable<Message>(
+ (observer) => {
+ this.channel = observer;
+ });
+
+ if (this.uri !== 'CLOSED') {
+ console.log('Channel is still open, uncanceling ' + this.uri);
+ this.canceled = false;
+ return observable;
+ }
+
+ let uri: string = this.backendUri + id + '/listen';
+ let service = this;
+
+ fetchEventSource(uri,{
+ headers: { 'X-Shard': shard },
+ async onopen(response) {
+ if (response.ok && response.status === 200) {
+ console.log('Opend channel ' + uri, response);
+ service.uri = uri;
+ service.canceled = false;
+ }
+ else if (
+ response.status >= 400 &&
+ response.status < 500 &&
+ response.status !== 429
+ ) {
+ console.error('Client side error when connecting to channel ' + uri, response);
+ throw new FatalError();
+ }
+ },
+ onmessage(event) {
+ console.debug('Received message on channel: ' + uri);
+ if (service.canceled)
+ throw new CanceledError();
+ service.processEvent(event);
+ },
+ onclose() {
+ console.log('Server closed channel ' + uri);
+ service.uri = "CLOSED";
+ throw new RetriableError();
+ },
+ onerror(error) {
+ console.log('Error on channel ' + uri, error);
+ if (error instanceof CanceledError || error instanceof FatalError) {
+ service.uri = "CLOSED";
+ throw error; // rethrow to stop the operation
+ }
+ else {
+ return 1000; // retry-intervall in ms
+ }
+ },
+ openWhenHidden: true
+ }).then(() => console.debug('Promise fullfilled for ' + uri));
+
+ return observable;
+ }
+
+ unlisten(): void {
+ console.log('Canceling channel ' + this.uri);
+ this.canceled = true;
+ }
+
+ // Processes custom event types
+ private processEvent(message: EventSourceMessage): void {
+ const parsed = message.data ? JSON.parse(message.data) : {};
+ switch (message.event) {
+ case 'message': {
+ this.channel.next(parsed);
+ break;
+ }
+ case 'error': {
+ // Not implemented server-side yet
+ console.error('Received error-message from server on channel ' + this.uri, message.data);
+ throw new FatalError(message.data);
+ }
+ // Add others if neccessary
+ default: {
+ console.error('Unhandled event:', message.event);
+ break;
+ }
+ }
+ }
+}
--- /dev/null
+export interface Chatroom
+{
+ id: string,
+ name: string,
+ shard: number
+}
--- /dev/null
+export interface Message
+{
+ id: string,
+ serialNumber: number,
+ timestamp: string,
+ user: string,
+ text: string,
+}
+++ /dev/null
-export interface Message
-{
- id: string,
- serialNumber: number,
- timestamp: string,
- user: string,
- text: string,
-}
+++ /dev/null
-import { TestBed } from '@angular/core/testing';
-
-import { UserService } from './user.service';
-
-describe('UserService', () => {
- let service: UserService;
-
- beforeEach(() => {
- TestBed.configureTestingModule({});
- service = TestBed.inject(UserService);
- });
-
- it('should be created', () => {
- expect(service).toBeTruthy();
- });
-});
+++ /dev/null
-import { Injectable } from '@angular/core';
-import { Router } from "@angular/router";
-
-@Injectable({
- providedIn: 'root'
-})
-export class UserService {
-
- private unknown: boolean = true;
- private name = '';
-
- constructor(private router: Router) { }
-
- assertUserisKnown(callback: Function): void {
- if(this.unknown) {
- this.router.navigate(['user']);
- }
- else {
- callback();
- }
- }
-
- setUser(name: string): void {
- console.log("New user: " + name);
- this.name = name;
- this.unknown = false;
- }
-
- getUser(): string {
- return this.name;
- }
-}
--- /dev/null
+import { TestBed } from '@angular/core/testing';
+
+import { UserService } from './user.service';
+
+describe('UserService', () => {
+ let service: UserService;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({});
+ service = TestBed.inject(UserService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+});
--- /dev/null
+import { Injectable } from '@angular/core';
+import { Router } from "@angular/router";
+
+@Injectable({
+ providedIn: 'root'
+})
+export class UserService {
+
+ private unknown: boolean = true;
+ private name = '';
+
+ constructor(private router: Router) { }
+
+ assertUserisKnown(callback: Function): void {
+ if(this.unknown) {
+ this.router.navigate(['user']);
+ }
+ else {
+ callback();
+ }
+ }
+
+ setUser(name: string): void {
+ console.log("New user: " + name);
+ this.name = name;
+ this.unknown = false;
+ }
+
+ getUser(): string {
+ return this.name;
+ }
+}