Retrofit Unexpected end of stream Connection - android

I'm currently trying to connect my android application to a local ASP.NET backend.
While doing so, I keep getting the error
Retrofit Unexpected end of stream Connection
I really have no clue where I'm wrong. I looked at other solutions, but none of those seem to help me.
I've read something about the content length being the issue. In my Startup.cs's configure method, I've noticed the following piece of code.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, DataInitializer dataInitializer)
{
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 204)
{
ctx.Response.ContentLength = 0;
}
});
However I have no idea if this is the cause of my issue.
Below I've added the rest of the code which might be part of the problem.
Startup.cs of .Net
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
//AddScopeds for each repository//
//...//
services.AddCors(o => o.AddPolicy("AllowAllOrigins", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
services.AddIdentity<IdentityUser, IdentityRole>(cfg => cfg.User.RequireUniqueEmail = true).AddEntityFrameworkStores<ApplicationDbContext>();
services.AddOpenApiDocument(
c =>
{
c.DocumentName = "apidocs";
c.Title = "Test API";
c.Version = "v1";
c.Description = "The Test API documentation description.";
c.DocumentProcessors.Add(new SecurityDefinitionAppender("JWT Token", new SwaggerSecurityScheme
{
Type = SwaggerSecuritySchemeType.ApiKey,
Name = "Authorization",
In = SwaggerSecurityApiKeyLocation.Header,
Description = "Copy 'Bearer' + valid JWT token into field"
}));
c.OperationProcessors.Add(new OperationSecurityScopeProcessor("JWT Token"));
}
);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme =
JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])),
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = true //Ensure token hasn't expired
};
});
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 8;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+";
options.User.RequireUniqueEmail = true;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, KlimaatMobielDataInitializer dataInitializer)
{
app.Use(async (ctx, next) =>
{
await next();
if (ctx.Response.StatusCode == 204)
{
ctx.Response.ContentLength = 0;
}
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCors("AllowAllOrigins"); //
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", #"Resources")),
RequestPath = new PathString("/Resources")
});
app.UseHttpsRedirection();
app.UseMvc();
app.UseSwaggerUi3();
app.UseSwagger();
app.UseAuthentication();
}
}
Retrofit interface
private const val BASE_URL = "http://10.0.2.2:5001/api/"
private val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.baseUrl(BASE_URL)
.build()
interface TestApiService {
#GET("material")
fun getMaterials():
Call<List<Material>>
}
object TestApi {
val retrofitService: KlimaatApiService by lazy {
retrofit.create(KlimaatApiService::class.java)
}
}
Using the interface
public fun getMaterialen() {
Timber.plant(Timber.DebugTree())
KlimaatApi.retrofitService.getMaterialen().enqueue(object : Callback<List<Material>> {
override fun onFailure(call: Call<List<Material>>, t: Throwable) {
_response.value = "Failure: " + t.message
Timber.e(t.message)
}
override fun onResponse(
call: Call<List<Material>>,
response: Response<List<Material>>
) {
if(!response.isSuccessful){
Timber.e("Code: ${response.code()}")
}
var materials = response.body()
for(mat in materials!!){
Timber.e(mat.name)
}
}
})
}

Related

How can I write to only one user with an existing WebSocket connection instead of to all users?

Here's what I have:
Here, incoming messages are sent to all users.
fun Route.chatSocket(roomController: RoomController) {
webSocket("/chat-socket" ) {
val session = call.sessions.get<ChatSession>()
if (session==null) {
close(CloseReason(CloseReason.Codes.VIOLATED_POLICY,"No session"))
return#webSocket
}
try {
roomController.onJoin(
username = session.username,
sessionId = session.sessionId,
socket = this
)
incoming.consumeEach { frame ->
if (frame is Frame.Text) {
roomController.sendMessage(
senderUsername = session.username,
message = frame.readText()
)
}
}
} catch (e: MemberAlredyExistExpetion) {
call.respond(HttpStatusCode.Conflict)
} finally {
roomController.tryDisconnect(session.username)
}
}
}
And here is the roomController:
class RoomController(
private val messageDataSource: MessageDataSource
) {
private val members = ConcurrentHashMap<String,Member>()
fun onJoin(
username:String,
sessionId:String,
socket: WebSocketSession
) {
if (members.containsKey(username)) {
throw MemberAlredyExistExpetion()
}
members[username] = Member(
username = username,
sessionId = sessionId,
socket = socket
)
}
suspend fun sendMessage(senderUsername: String, message: String) {
members.values.forEach { member ->
val messageEntity = Message(
text = message,
username = senderUsername,
timestamp = System.currentTimeMillis()
)
messageDataSource.insertMessage(messageEntity)
val parsedMessage = Json.encodeToString(messageEntity)
member.socket.send(Frame.Text(parsedMessage))
}
}
Here I have tried to implement a command with which I can write directly to a user. But it don`t work.
fun Route.chatToOne(roomController: RoomController) {
webSocket("/whisper") {
val session = call.sessions.get<ChatSessionToOne>()
if (session==null) {
close(CloseReason(CloseReason.Codes.VIOLATED_POLICY,"No Session"))
return#webSocket
}
try {
incoming.consumeEach { frame ->
if (frame is Frame.Text) {
roomController.sendMessageToOneUser(
senderUsername = session.username,
targetUsername = session.targetusername,
message = frame.readText()
)
}
}
} catch (e: MemberAlredyExistExpetion) {
call.respond(HttpStatusCode.Conflict)
}
}
}
And here the code from the roomController:
suspend fun sendMessageToOneUser(senderUsername: String, targetUsername :String, message: String) {
members.values.forEach { member ->
if (member.username == targetUsername) {
val messageEntity = Message(
text = message,
username = targetUsername,
timestamp = System.currentTimeMillis()
)
messageDataSource.insertMessage(messageEntity)
val parsedMessage = Json.encodeToString(messageEntity)
member.socket.send(Frame.Text(parsedMessage))
}
}
}
How can I write to only one user with an existing WebSocket connection instead of to all users?

How to keep the user logged in even after closing the app in ionic/angular project?

I am new to angular/ionic and I am assigned with a project where the user supposed to be logged in even after he close the application unless logging out. can anyone suggest me how to modify the following code?
login.page.ts
import { AuthenticationService } from '../../services/authentication/authentication.service';
import {
ToastController,
AlertController,
NavController,
ModalController,
Platform,
} from '#ionic/angular';
import { FormBuilder, Validators, FormGroup } from '#angular/forms';
import { ApiService } from '../../services/api/api.service';
import { Router } from '#angular/router';
import { crm, environment } from '../../../environments/environment';
import { DataService } from '../../services/data/data.service';
import { ToastService } from '../../services/toast/toast.service';
import { AlertService } from '../../services/alert/alert.service';
import { ForgotPasswordModalPage } from '../forgot-password-modal/forgot-password-modal.page';
import { Device } from '#ionic-native/device/ngx';
import { FcmService } from '../../services/fcm/fcm.service';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { LoadingService } from 'src/app/services/loading/loading.service';
import { ServerService } from 'src/app/services/server/server.service';
import * as moment from 'moment';
import { AppComponent } from '../../app.component';
#Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
loginForm: FormGroup;
development: boolean;
counts: number = 0;
platformName: string;
settings: any;
constructor(
private authService: AuthenticationService,
public formBuilder: FormBuilder,
private api: ApiService,
private router: Router,
private alert: AlertService,
private dataService: DataService,
private toast: ToastService,
private navCtrl: NavController,
private modalCtrl: ModalController,
private device: Device,
private fcmService: FcmService,
private splashScreen: SplashScreen,
private loadingService: LoadingService,
private server: ServerService,
private alertCtrl: AlertController,
private platform: Platform,
private app: AppComponent,
) {
this.initForm();
}
ngOnInit(): void {
this.setupServerUrl();
}
async setSettings() {
console.log('settings called in appcomp');
// check if in storage get it from storage
this.dataService.getStorageData('settings').then((data) => {
if (data != null) {
this.settings = JSON.parse(data);
console.log('seetings from storage:', this.settings);
// this.dataService.setData('settings', this.settings)
} else {
// not found in storage get from api
this.getSettingsApi();
}
});
}
async getSettingsApi() {
// this.loadingService.loading();
let mainLogos = document.getElementsByClassName('logo');
for (let i = 0; i < mainLogos.length; i++) {
mainLogos[i].setAttribute('src', 'assets/img/spinner.gif');
}
await this.api.get(crm.SETTINGS).subscribe((res) => {
console.log('the api is ', this.api.url);
// Note the api I supposed to get
console.log('setting from appcomp api: ', res);
if (res['code'] === '000') {
this.settings = res;
// this.dataService.setData('settings', this.settings)
console.log('settings from appcomp done');
this.dataService.setStorageData('settings', res);
for (let i = 0; i < mainLogos.length; i++) {
mainLogos[i].setAttribute('src', this.settings.image_id.src);
}
// this.loadingService.dismissLoading();
}
});
}
// async setSettings() {
// console.log('settings from login')
// await this.dataService.getStorageData('settings').then( data => {
// console.log('seetings from storage: ', data)
// if (data != null) {
// this.settings = JSON.parse(data);
// this.dataService.setData('settings', this.settings)
// }else { // not found in storage get from api
// this.api.get(crm.SETTINGS).subscribe(res => {
// if (res['code'] === '000') {
//
// this.settings = res
// this.dataService.setData('settings', this.settings)
// this.dataService.setStorageData('settings', res);
// // this.settingsService.data = this.settings
//
// // toolbar logo
// // let mainLogos = document.getElementsByClassName('logo')
// // for (let i = 0; i < mainLogos.length; i++) {
// // mainLogos[i].setAttribute('src', this.settings.image_id.src)
// // }
// }
// })
// }
// })
// }
// Note : server set up and function coming from server.service
setupServerUrl() {
this.dataService.getStorageData('url').then((res) => {
if (res) {
this.server.url = JSON.parse(res);
console.log('server', res);
console.log('server result123: ', this.server.url);
console.log('login result123: ', this.server.login_url);
this.server.login_url = JSON.parse(res);
console.log('login', res);
// console.log('have result serve url:', this.server.url);
// console.log('have result login url:', this.server.login_url);
this.getApiDomain('https://oasis.api.app360.my/');
} else {
console.log('empty result url:', this.server.url);
this.getApiDomain('oasis.member.app360.my');
}
});
}
ionViewDidEnter() {
if (this.server.login_url === this.server.login_dev) {
this.development = true;
}
if (this.server.login_url === this.server.login_prod) {
this.development = false;
}
// this.setup()
// this.development = true;
// break;
// case this.server.prod:
// this.server.url = this.server.prod // added by me
// this.development = false;
// break;
// }
// })
}
initForm() {
this.loginForm = this.formBuilder.group({
email: [
'',
Validators.compose([
Validators.pattern('.+#.+\\..+'),
Validators.required,
]),
],
password: ['', Validators.required],
});
}
async getApiDomain(urlDomain: String) {
console.log('beforeeee', this.server.url);
await this.api
.getBeforeLogin(crm.API_DOMAIN, '', '?url=' + urlDomain)
.subscribe((res) => {
if (res['code'] === '000') {
// console.log('resulttt',res['domain'])
this.server.url = 'https://' + res['domain'] + '/';
this.server.prod = 'https://' + res['domain'] + '/';
this.server.secret = res['api_key'];
// this.server.url = "http://oasis.api.app360.my/"
console.log('afterrrr', this.server.url);
// console.log('afterrrr', this.server.secret);
this.getSettingsApi();
this.setHome();
this.checkToken();
}
});
}
// resolveSettings() {
// console.log('settings from login')
// this.api.get(crm.SETTINGS).subscribe(res => {
// if (res['code'] === '000') {
//
// this.settings = res
// this.dataService.setData('settings', this.settings)
// // this.settingsService.data = this.settings
//
// // toolbar logo
// let mainLogos = document.getElementsByClassName('logo')
// for (let i = 0; i < mainLogos.length; i++) {
// mainLogos[i].setAttribute('src', this.settings.image_id.src)
// }
//
//
// }
// })
// }
setup() {
console.log('testttt', this.settings);
// set toolbar color
let toolbars = document.getElementsByTagName('ion-toolbar');
for (let i = 0; i < toolbars.length; i++) {
toolbars[i].setAttribute(
'style',
`--background: ${this.settings.colours.colour_menu_background}`,
);
}
// toolbar logo
let mainLogos = document.getElementsByClassName('logo');
for (let i = 0; i < mainLogos.length; i++) {
mainLogos[i].setAttribute('src', this.settings.image_id.src);
console.log('wahaha', this.settings.image_id.src);
}
let button = document.getElementsByClassName('login-btn')[0];
button.setAttribute(
'style',
`--background: ${this.settings.colours.colour_button1};
--color: ${this.settings.colours.colour_menu_font}`,
);
console.log('endend');
}
async login(form) {
await this.loadingService.loading();
form.platform = this.device.platform;
form.device_type = this.device.model;
form.platform_token = this.device.uuid;
form.push_token = this.fcmService.pushToken;
console.log('form', form);
await this.api.post(crm.LOGIN, form).subscribe((res) => {
this.loadingService.dismissLoading();
console.log('login', res);
if (res.code === '000') {
console.log('code', res.code);
this.toast.showToast('Login Successful');
//proceed with auth
this.doAuth(res);
} else {
// let message = res.status+':'+res.statusText+'<br/>'+res.error.code+':'+res.error.message
this.alert.showAlert({
header: 'Error: ' + res.error.code,
message: res.error.message,
});
console.log('error', res);
}
});
}
async forgotPassword() {
console.log('do forgot password');
let modal = await this.modalCtrl.create({
component: ForgotPasswordModalPage,
cssClass: 'forgot-password',
});
return await modal.present();
}
doAuth(data) {
console.log('from do auth: ', data);
this.authService.login(data).then((res) => {
if (res) {
this.navCtrl.navigateRoot('/tabs/tabs/home');
console.log('doauth', data);
}
});
}
counter() {
this.counts++;
console.log(this.counts);
if (this.counts >= 8) this.presentPrompt(); //TODO: change to 8
}
async presentPrompt() {
this.counts = 0;
const alert = await this.alertCtrl.create({
header: ' ',
inputs: [
{
name: 'passcode',
placeholder: 'Passcode',
type: 'password',
},
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: (data) => {
console.log('Cancel clicked');
},
},
{
text: 'Ok',
handler: (data) => {
this.api
.getBeforeLogin(crm.SWITCH, null, `?passcode=${data.passcode}`)
.subscribe((res) => {
if (res['code'] == '000') {
this.changeServer();
console.log('Switched');
this.toast.showToast('Switched');
// this.loadingService.dismissLoading();
} else {
this.alert.showAlert({
header: 'Error: ' + res['code'],
message: res['error'],
});
console.log('error', res);
}
});
},
},
],
cssClass: 'alertCustomCss',
backdropDismiss: false,
});
await alert.present();
}
changeServer() {
this.server.switchURL();
switch (this.server.login_url) {
case this.server.login_prod:
this.development = false;
// this.api.url = this.server.prod;
this.server.login_url = this.server.login_prod;
console.log('api url', this.server.login_url);
break;
case this.server.login_dev:
this.development = true;
this.server.login_url = this.server.login_dev;
console.log('api url', this.server.login_url);
break;
}
this.checkDownload();
// Note :
this.getApiDomain('https://oasis.api.app360.my/');
// this.getApiDomain('com.apppay.cohibacustomer');
}
async checkDownload() {
await this.dataService.getStorageData('stats_for_dev').then((res) => {
if (!res) {
let params = {};
if (this.platform.is('android')) {
this.platformName = 'android';
} else if (this.platform.is('ios')) {
this.platformName = 'ios';
} else {
this.platformName = 'web';
}
params['refno'] = moment().format('YYYYMMDDHHmm');
params['data'] = [
{
action_cd: 'install',
user_id: null,
item_id: this.platformName[0], // a for android, i for ios
cnt: 1,
created_ts: moment().format('YYYY-M-D'),
},
];
} else {
console.log('have stats', JSON.parse(res));
}
});
}
async setHome() {
await this.api.get(crm.HOME).subscribe((res) => {
console.log('home>>>>>>>>>>>>>>>>>>>>>>>>> ', res);
this.dataService.setStorageData('home', res);
this.dataService.setData('home', res);
return res;
});
}
async checkToken() {
await this.dataService.getStorageData('member').then((res) => {
if (res != null) {
let token = res ? JSON.parse(res) : null;
token = token['secret'] ? token['secret'] : null;
if (token) {
this.authService.authenticationState.next(true);
if (this.server.url != this.server.check_url) {
this.navCtrl.navigateRoot('/tabs/tabs/home');
}
} else {
this.authService.authenticationState.next(false);
this.navCtrl.navigateRoot('');
}
}
});
}
}
authentication.service.ts
import { Platform, NavController } from "#ionic/angular";
import { Injectable } from "#angular/core";
import { Storage } from "#ionic/storage";
import { BehaviorSubject } from "rxjs";
import { DataService } from "../data/data.service";
import { ObservablesService } from "../observable/observables.service";
import { SplashScreen } from "#ionic-native/splash-screen/ngx";
import { Badge } from "#ionic-native/badge/ngx";
import { ServerService } from "../server/server.service";
const TOKEN_KEY = "auth-token";
export interface OcOAuth {
success: number;
error: any;
data: {
access_token: string;
expire_in: number;
token_type: string;
};
}
#Injectable({
providedIn: "root",
})
export class AuthenticationService {
authenticationState = new BehaviorSubject(false);
constructor(
private storage: Storage,
private plt: Platform,
private dataService: DataService,
private observable: ObservablesService,
private splashScreen: SplashScreen,
private navCtrl: NavController,
private badge: Badge,
private server: ServerService
) {
this.plt.ready().then(() => {
this.checkToken();
});
this.observable.unread().subscribe((res) => {
this.badge.set(res);
console.log("observed unread", res);
});
}
async checkToken() {
await this.storage.get("member").then((res) => {
if (res != null) {
let token = res ? JSON.parse(res) : null;
token = token["secret"] ? token["secret"] : null;
if (token) {
this.authenticationState.next(true);
if (this.server.url != this.server.check_url) {
this.navCtrl.navigateRoot("/tabs/tabs/home");
}
// console.log('server url: ', this.server.url);
//
} else {
this.authenticationState.next(false);
this.navCtrl.navigateRoot("");
}
}
});
}
login(data) {
return this.storage.set(TOKEN_KEY, "Bearer 1234").then(() => {
console.log("auth login", TOKEN_KEY);
this.dataService.setStorageData("member", data);
this.dataService.setData("member", data);
// this.dataService.setStorageData('profile', data.user)
this.observable.user.next(data.user);
this.authenticationState.next(true);
return true;
});
}
logout() {
return this.storage.remove("member").then(() => {
this.badge.clear();
this.authenticationState.next(false);
});
}
isAuthenticated() {
return this.authenticationState.value;
}
}
Firstly your code is so long that can not help with that but i can explain what u must do the concept is when you logged in successfully u must get a token and store that.
After at app openning you must check that stored token. If that token still available u can navigate to main screen. Else u must navigate to ur login page.
login() {
const attempt = login(username,pw)
if(attempt.status === 200) {
//if username and pw is correct web service must be return token
this.storage.set("token", attempt.token)
navigate("where u want")
} else {
//Error when username or pw wrong.
}
If u using ionic u must check ur token in app.component.ts
const token = await this.storage.get("token")
const checkTokenIsAvailable = await checkToken(token)
if(checkTokenIsAvailable) {
navigate("where u want")
//Token is still available
} else {
navigate("login screen")
}
That's all.
In your app.component.ts after platform is ready, add
if(this.authenticationService.isAuthenticated())
{
//Navigate to Home Page
}
else{
//Navigate to Login Page
}
so I was able to solve the issue with the subscribe() method. Inside platfrom.ready I called this
this.authService.authenticationState.subscribe((state) => {
if (state) {
this.navCtrl.navigateRoot("/tabs/tabs/home");
} else {
this.navCtrl.navigateRoot("");
}
});

Weird angular issue on Samsung phone

I have an angular app where I am seeing a weird issue with the menu component on my Samsung S20 phone (it appears to work just fine in desktop Chrome). When I focus an input field on PicksComponent and then select my hamburger button to toggle my menu it appears for a second then disappears and unselects my input field. When I tap the hamburger button again it works fine. The MenuComponent shouldn't be communicating with the PicksComponent in any way so I have no idea what's going on.
app-component.html
<main id="container">
<div class='banner'>websitename</div>
<app-menu></app-menu>
<div id="routerOutlet">
<router-outlet></router-outlet>
</div>
</main>
menu-component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from "#angular/router";
import { ManageLoginService } from "../manage-login.service";
#Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css']
})
export class MenuComponent implements OnInit {
constructor(private router: Router,private manageLoginService : ManageLoginService) { }
mobileWidth: number = 500;
screenWidth: number = window.innerWidth;
displayMenuItems: boolean = false;
loggedIn : boolean = false;
logout() {
localStorage.clear();
this.router.navigateByUrl("/login");
}
checkMenu() {
this.screenWidth = window.innerWidth;
if(this.screenWidth > this.mobileWidth) {
this.displayMenuItems = true;
}
else {
this.displayMenuItems = false;
}
}
toggleMenu() {
this.displayMenuItems = !this.displayMenuItems;
}
ngOnInit() {
this.checkMenu();
this.manageLoginService.isUserLoggedIn.subscribe(loggedInStatus => this.loggedIn = loggedInStatus)
}
}
</ul>
picks-component.ts
import { Component, OnInit,ViewChild,ElementRef} from '#angular/core';
import { Router } from "#angular/router";
import { DataService } from "../data.service";
#Component({
selector: 'app-picks',
templateUrl: './picks.component.html',
styleUrls: ['./picks.component.css'],
})
export class PicksComponent implements OnInit {
constructor(private dataService : DataService,private router: Router) { }
#ViewChild("playerOne",{static:false}) playerOneField: ElementRef;
#ViewChild("playerTwo",{static:false}) playerTwoField: ElementRef;
#ViewChild("playerThree",{static:false}) playerThreeField: ElementRef;
#ViewChild("playerFour",{static:false}) playerFourField: ElementRef;
#ViewChild("playerFive",{static:false}) playerFiveField: ElementRef;
title: string = 'Submit Picks';
suggestions : any = {"playerOne":[],"playerTwo":[],"playerThree":[],"playerFour":[],"playerFive":[]};
picks : any = {"playerOne":"","playerTwo":"","playerThree":"","playerFour":"","playerFive":""};
picksForm : any = {"token":"","players":this.picks};
enableSuggestions: boolean = true;
formResponse : any;
formValid : boolean = true;
formErrors : string;
keys : any;
picksSubmitted : boolean = false;
focus(elementName : any): void {
this[elementName].nativeElement.focus();
}
displayPlayers(player :any) {
console.log("HMM");
localStorage.setItem("picks",JSON.stringify(this.picks));
if(this.picks[player].length >= 3 && this.enableSuggestions) {
this.dataService.getSuggestions(this.picks[player]).subscribe(suggestions => this.suggestions[player] = suggestions);
}
else {
this.enableSuggestions = true;
this.suggestions[player] = [];
}
}
submitForm(form :any) {
if(this.validateForm()) {
this.picksForm.token = localStorage.getItem("token");
this.dataService.sendEmail(form).subscribe(formResponse => this.processResponse(formResponse));
}
else {
this.formValid = false;
}
}
processResponse(response :any) {
this.formResponse = response;
if(this.formResponse.error) {
this.formValid = false;
this.formErrors = this.formResponse.message;
}
else {
localStorage.removeItem("picks");
this.picksSubmitted = true;
}
}
select(suggestion : any,player :any) {
this.enableSuggestions = false;
this.picks[player] = suggestion.forename + " " + suggestion.surname;
this.suggestions[player] = [];
localStorage.setItem("picks",JSON.stringify(this.picks));
}
resetForm() {
this.picks.playerOne = "";
this.picks.playerTwo = "";
this.picks.playerThree = "";
this.picks.playerFour = "";
this.picks.playerFive = "";
}
hideSuggestions() {
this.suggestions.playerOne = [];
this.suggestions.playerTwo = [];
this.suggestions.playerThree = [];
this.suggestions.playerFour = [];
this.suggestions.playerFive = [];
}
validateForm() : boolean {
// Create array from object
this.keys = Object.values(this.picks);
// Iterate over array
for(const key of this.keys) {
if(key.length < 2) {
this.formErrors = "Please do not leave any picks blank.";
return false;
}
}
return true;
}
ngOnInit() {
if(localStorage.getItem("picks")) {
this.picks = JSON.parse(localStorage.getItem("picks"));
this.picksForm = {"token":"","players":this.picks};
}
setTimeout (() => { this.hideSuggestions(); }, 1000);
}
}
Anyone got any idea what could be causing this? Please let me know if you require any more of my code to help. Not sure if there is some issue with mobile chrome or whether I've made a mistake as I'm still fairly new to Angular.
There was a window:resize binding in the menu component which was getting triggered when the keyboard appearing or disappearing on mobile was causing the height of the window to change. I modified the method to only trigger when the width was changed and that fixed it.

how to play video stream from websocket url on exoplayer?

I am trying to stream a video from websocket url in android. The url looks something like this ws://abc.com:80/api/streaming/download/mp4/ . I am not really sure how to proceed because this thing is new for me. I tried searching on the internet and i found only one solution on stackoverflow which says to connect with websocket using okhttp and then use okhttpdatasource with Exoplayer. So I tried connecting to websocket url using okhttp and i am successfully recieving bytestream. Here is the code:
public void startListen() {
// Request request = new Request.Builder().url(mContext.getResources().getString(R.string.ws_url)).build();
Request request = new Request.Builder().url(getApplicationContext().getResources().getString(R.string.myUrl)).build();
//final ByteBuffer buf = ByteBuffer.allocate(MediaBlockSize);
mWebSocket = mOkHttpClient.newWebSocket(request, new WebSocketListener() {
#Override
public void onOpen(WebSocket webSocket, Response response) {
super.onOpen(webSocket, response);
Log.d("MNMN", String.valueOf(response));
}
#Override
public void onMessage(WebSocket webSocket, String text) {
super.onMessage(webSocket, text);
Log.d("MNMN", "text = " + text);
}
#Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
super.onMessage(webSocket, bytes);
//Log.d("MNMNx", "size = " + bytes.size());
final byte b[] = bytes.toByteArray();
try {
mOutputStream.write(b);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onClosing(WebSocket webSocket, int code, String reason) {
super.onClosing(webSocket, code, reason);
}
#Override
public void onClosed(WebSocket webSocket, int code, String reason) {
super.onClosed(webSocket, code, reason);
}
#Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
super.onFailure(webSocket, t, response);
Log.d("MNMN", String.valueOf(response));
}
});
}
But i don't really know how to make it work with Exoplayer. Exoplayer has extension for okhttpdatasource but i didn't find any good tutorial of using it. Can someone guide me how can I use stream received from okhttp with exoplayer to play the video?
I know its late to answer. But in case someone else looking for this.
I had similar situation. I don't think OkHttpDataSource is meant for wss.
I came up with my own Exo DataSource that works as expected.
First collect the data received from wss using OkHttp's WebSocketListener
class WssDataStreamCollector #Inject constructor() : WebSocketListener() {
private val wssData = ConcurrentSkipListSet<ByteString>()
override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
wssData.add(bytes)
}
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
super.onClosing(webSocket, code, reason)
wssData.removeAll(wssData)
}
fun canStream(): Boolean {
return wssData.size > 0
}
fun getNextStream(): ByteString {
return wssData.pollFirst()
}
}
Create the DataSource
class WssStreamDataSource : BaseDataSource(true) {
#Inject
lateinit var httpClient: OkHttpClient
#Inject
lateinit var dataStreamCollector: WssDataStreamCollector
var webSocketClient: WebSocket? = null
private var currentByteStream: ByteArray? = null
private var currentPosition = 0;
private var remainingBytes = 0;
override fun open(dataSpec: DataSpec): Long {
// Form the request and open the socket.
// Provide the listener
// which collects the data for us (Previous class).
webSocketClient = httpClient.newWebSocket(
Request.Builder().apply {
dataSpec.httpRequestHeaders.forEach { entry ->
addHeader(entry.key, entry.value)
}
}.url(dataSpec.uri.toString()).build(),
dataStreamCollector
)
return -1 // Return -1 as the size is unknown (streaming)
}
override fun getUri(): Uri? {
webSocketClient?.request()?.url?.let {
return Uri.parse(it.toString())
}
return null
}
override fun read(target: ByteArray, offset: Int, length: Int): Int {
// return 0 (nothing read) when no data present...
if (currentByteStream == null && !dataStreamCollector.canStream()) {
return 0
}
// parse one (data) ByteString at a time.
// reset the current position and remaining bytes
// for every new data
if (currentByteStream == null) {
currentByteStream = dataStreamCollector.getNextStream().toByteArray()
currentPosition = 0
remainingBytes = currentByteStream?.size ?: 0
}
val readSize = min(length, remainingBytes)
currentByteStream?.copyInto(target, offset, currentPosition, currentPosition + readSize)
currentPosition += readSize
remainingBytes -= readSize
// once the data is read set currentByteStream to null
// so the next data would be collected to process in next
// iteration.
if (remainingBytes == 0) {
currentByteStream = null
}
return readSize
}
override fun close() {
// close the socket and relase the resources
webSocketClient?.cancel()
}
// Factory class for DataSource
class Factory : DataSource.Factory {
override fun createDataSource(): DataSource = WssStreamDataSource()
}
}
That's all, you are good to go.
Now use ProgressiveMediaSource with the DataSource we created like below.
SimpleExoPlayer(yourBuilder).apply {
setVideoSurfaceView(surfaceView)
val mediaItem = MediaItem.fromUri(uri) // URI with wss://
val factory = ProgressiveMediaSource.Factory(WssStreamDataSource.Factory())
addMediaSource(factory.createMediaSource(mediaItem))
prepare()
playWhenReady = true
play()
}

Client registration failed

I have developped an ibm mobile first application with adapter authorization and challenged handler.I have added an android environment and want to test it against production server, so I deployed the apk on my dev tablet.
I've seen that when trying to invoke a remote adapater worklight tries to get ClientInstanceId by executing a cordova method "WLAuthorizationManagerPlugingetClientInstanceIdHeader". This request results always in a timeout and I can see in console one new entru: "Uncaught (in promise) adapter-communication-error". The method exits with "WL.Logger.debug('Client registration failed with error: ' + JSON.stringify(error));"
Edited: Login flow:
Login implementation:
import {UserModel} from 'app-user';
import {UserService} from 'app-user-service';
import {AppSettingsService} from 'app-settings';
import {AppMasterDataService} from "../master-data/app-master-data-service";
import jsSha from 'js-sha';
import {UserRepository} from "user-repository";
import {NetworkInformation} from ../../infrastructure/phonegap/plugins/network-information';
export class LoggedInUser{
public static inject = [UserService, AppSettingsService, AppMasterDataService, UserRepository];
public info: UserModel;
public isLoggedIn: boolean;
private singleStepAuthRealmChallengeHandler: any;
private _getUserInfoPromise: Promise<UserModel>;
private _listeners: Array<(success: boolean, error: string) => void> = [];
private lastCredentials: any;
constructor(private _userService: UserService, private _settingsService: AppSettingsService, private _masterDataService: AppMasterDataService, private _userRepo: UserRepository){
if(typeof WL != "undefined"){
this.singleStepAuthRealmChallengeHandler = WL.Client.createChallengeHandler('GicarAuthRealm');
this.singleStepAuthRealmChallengeHandler.isCustomResponse = this.isCustomResponse.bind(this);
this.singleStepAuthRealmChallengeHandler.handleChallenge = this.handleChallenge.bind(this);
}
}
public async initializeUserInfo(): Promise<void>{
return this.executeLogOut(null, null);
}
public addLoginEventListener(callback: (success: boolean, error: string) => void){
if(!this._listeners.some(x => x === callback)){
this._listeners.push(callback);
}
}
public removeLoginEventListener(callback: (success: boolean, error: string) => void){
let index = this._listeners.indexOf(callback);
if(index >= 0){
this._listeners.splice(index, 1);
}
}
private raiseLoginEvent(success: boolean, error?: string){
for (var listener of this._listeners){
try {
listener(success, error);
}catch (e){
this.removeLoginEventListener(listener);
}
}
}
public prepareLogin(){
if(NetworkInformation.connected())
this._getUserInfoPromise = this._userService.getUserInfo();
}
public async executeLogIn(userName: string, password: string){//: Promise<boolean>{
await this.executeLogOut(userName, password);
if(this.singleStepAuthRealmChallengeHandler){
if(NetworkInformation.connected()){
var userNameSha = new jsSha("SHA-512", "TEXT");
userNameSha.update(userName);
var userNameHash = userNameSha.getHash("B64");
var passwordSha = new jsSha("SHA-512", "TEXT");
passwordSha.update(password);
var passwordHash = passwordSha.getHash("B64");
this.lastCredentials = {
userName: userNameHash,
password: passwordHash
};
var invocationData = {
adapter : "GicarAuthAdapter",
procedure : "submitAuthentication",
parameters : [ userName, window.btoa(userName + ':' + password) ]
};
this.singleStepAuthRealmChallengeHandler.submitAdapterAuthentication(invocationData);
}else {
this.doDisconnectedLogin(userName, password);
}
}
else{
this._userService.logIn(userName, password)
.then(info =>{
this.info = info;
this.isLoggedIn = typeof info !== 'undefined' && info != null;
this.raiseLoginEvent(this.isLoggedIn);
}).catch(e =>{
this.isLoggedIn = false;
this.info = null;
this.raiseLoginEvent(false, e.message ? e.message : e.toString())
});
}
}
private async doDisconnectedLogin(userName: string, password: string){
var userNameSha = new jsSha("SHA-512", "TEXT");
userNameSha.update(userName);
var userNameHash = userNameSha.getHash("B64");
var passwordSha = new jsSha("SHA-512", "TEXT");
passwordSha.update(password);
var passwordHash = passwordSha.getHash("B64");
var persisted = await this._userRepo.findUserByUserName(userNameHash);
let success = persisted && persisted.password == passwordHash;
this.info = persisted;
this.isLoggedIn = success;
this.raiseLoginEvent(success, success ? null : 'user-invalid-credentials');
}
public executeLogOut(userName: string, password: string): Promise<void>{
this.lastCredentials = null;
if(NetworkInformation.connected()){
return this._userService.logOut(this.info).then(() =>{
this.isLoggedIn = false;
this.info = null;
});
}
else
return Promise.resolve();
}
private isCustomResponse(response: any): boolean{
if (!response || !response.responseJSON || response.responseText === null) {
return false;
}
if (typeof(response.responseJSON.authRequired) !== 'undefined'){
return true;
} else {
return false;
}
}
private async handleChallenge(response: JQueryXHR){
var authRequired = response.responseJSON.authRequired;
if(authRequired == true){
this.info == null;
this.raiseLoginEvent(false, response.responseJSON.errorMessage);
}else {
try {
if(this.info == null){
this.singleStepAuthRealmChallengeHandler.submitSuccess();
this.info = await this._getUserInfoPromise;
await this._masterDataService.initializeMasterData(false);
if(this.lastCredentials){
await this._userRepo.saveUser({
entityId: this.lastCredentials.userName,
firstName: this.info.firstName,
lastName: this.info.lastName,
fullName: this.info.fullName,
email: this.info.email,
nif: this.info.nif,
address: this.info.address,
userName: this.lastCredentials.userName,
password: this.lastCredentials.password
});
}
this.isLoggedIn = true;
this.raiseLoginEvent(true);
}
}catch (error){
this.raiseLoginEvent(false, error.message ? error.message : error.toString());
}
}
}
}
I think I found the issue.
In order to support several environment, including desktopbrowser's one, I'm calling MFP adapter using the "old" method:`
WL.Client.invokeProcedure({
adapter: "UserServiceAdapter",
procedure: 'getUserInfo'
parameters: [],
compressResponse: false
},{
timeout:30000,
onSuccess: handleSuccess,
onFailure: handleFailure
});
If I replace above code by:
var resourceRequest = new WLResourceRequest("/adapters/UserServiceAdapter/getUserInfo", WLResourceRequest.GET, 30000);
resourceRequest.send().then(
handleSuccess,
handleFailure
);
It's working fine on Android.
It seems I have to check the environment in order to decide the adapter invocation method

Categories

Resources