How to correctly dispose SpeechToText in Dart? - flutter

So, in my Flutter project I have two routes, the second one uses the SpeechToText package. When I go from the first to the second route for the first time everything works fine but when I go back and go to the second one again the onStatus method is not called when it should be.
I did a little debugging and here is what I found: The onStatus method is set in the SpeechToText().initialize method. It initializes the methods if the variable _initWorked false. But when I open the route the second time the variable is already set to true even though I have a completely different instance of SpeechToText.
This leads me to think that it is still activated on an OS-level. But I just cannot find a way to entirely dispose it. Is there a way to do so, is it a bug in the package itself or is it because of something completely different?
Any help would be highly appreciated :)

SpeechToText is a Singleton, you always get the same instance https://github.com/csdcorp/speech_to_text/blob/1a0864910db88eb83cdde113b447baa7405eaa7e/speech_to_text/lib/speech_to_text.dart#L89
source code snippet
class SpeechToText {
...
static final SpeechToText _instance = SpeechToText.withMethodChannel();
...
factory SpeechToText() => _instance;
To dispose SpeechToText you can call stop()
it will cal destroyRecognizer() and do speechRecognizer?.destroy(); speechRecognizer = null;
https://github.com/csdcorp/speech_to_text/blob/1a0864910db88eb83cdde113b447baa7405eaa7e/speech_to_text/android/src/main/kotlin/com/csdcorp/speech_to_text/SpeechToTextPlugin.kt#L511
Android source code snippet
public class SpeechToTextPlugin : ...
...
private var speechRecognizer: SpeechRecognizer? = null
...
"stop" -> stopListening(result)
...
private fun stopListening(result: Result) {
if (sdkVersionTooLow() || isNotInitialized() || isNotListening()) {
result.success(false)
return
}
debugLog("Stop listening")
handler.post {
run {
speechRecognizer?.stopListening()
}
}
if ( !recognizerStops ) {
destroyRecognizer()
}
notifyListening(isRecording = false)
result.success(true)
debugLog("Stop listening done")
}
...
private fun destroyRecognizer() {
handler.postDelayed( {
run {
debugLog("Recognizer destroy")
speechRecognizer?.destroy();
speechRecognizer = null;
}
}, 50 )
}

Related

Time-driven lifetime scope in singleton ASP.NET Web API controller

Consider the web controller that implements some API by wrapping downstream service that requires token to be called. The token has the expiration, so I'm after some kind of time-driven scope that re-acquires the token and re-creates client in case the token is expired:
MyController: Controller
{
IServiceAPI _downstreamServcie;
MyController (IServiceAPI downstreamService)
{
}
}
....
builder.Register(c => {
Token token = generateToken() ..
return new ServiceAPIClient(token) ;
})
.As<IServiceAPI>()
I don't want to register MyController with per-request-scope because of performance issues.
Having spring background, such kind of captive dependency is resolved in spring by injecting singleton dynamic proxy that forwards the call to the right scoped-object (request/session/custom).
What would be the right way to implement the same with Autofac?
Thanks
[UPDATE]
Digging into Autofac documentation, I've found IResolveMiddleware interface that can be used to dynamically create/change scope :
class TokenScopeResolverMiddleware : IResolveMiddleware {
private ISharingLifetimeScope _currentTokenScope;
private ISharingLifetimeScope _prevTokenScope;
public void Execute(ResolveRequestContext context, Action<ResolveRequestContext> next) {
if (null == _currentTokenScope) {
lock (this) {
if (null == _currentTokenScope) {
RolloverScope(context);
}
}
}
if (!CanUseCurrentToken()) {
lock (this) {
if (!CanUseCurrentToken()) {
RolloverScope(context);
}
}
}
context.ChangeScope(_currentTokenScope);
next(context);
}
private bool CanUseCurrentToken() {
AuthenticationResult authResult = _currentTokenScope.Resolve<AuthenticationResult>();
TimeSpan expiresIn = authResult.ExpiresOn - DateTime.Now;
return expiresIn > TimeSpan.FromSeconds(20);
}
private void RolloverScope(ResolveRequestContext context) {
if (null != _prevTokenScope) {
_prevTokenScope.Dispose();
}
_prevTokenScope = _currentTokenScope; // give another `expiration time` grace period before disposing token scope
_currentTokenScope =
context.ActivationScope.RootLifetimeScope.BeginLifetimeScope("token") as ISharingLifetimeScope;
}
public PipelinePhase Phase { get; } = PipelinePhase.ScopeSelection;
}
Usage :
builder.Register(c => {
AuthenticationResult result = // acquire token
return result;
})
.InstancePerMatchingLifetimeScope("token");
builder.Register(c => {
return new Client(c.Resolve<AuthenticationResult>().Token)
})
.InstancePerMatchingLifetimeScope("token");
builder.RegisterServiceMiddleware<Client>(new TokenScopeResolverMiddleware());
Any better suggestions ?
I think you're likely looking for the Func<T> relationship, or something like it, where you inject a factory that dynamically resolves the client as you need it.
public class MyController
{
private readonly Func<IClient> _clientFactory;
public MyController(Func<IClient> clientFactory)
{
this._clientFactory = clientFactory;
}
public void DoWork()
{
var client = this._clientFactory();
client.CallApi();
}
}
Your lambda could be just about anything as long as it runs synchronously. Don't forget DI is more about injecting dependencies (object construction) than it is about managing your application's state, orchestrating logic, or executing factories on your behalf, though admittedly it's pretty convenient to try to multipurpose it in those ways.
var builder = new ContainerBuilder();
builder.Register(ctx =>
{
var token = GetOrRefreshToken();
return new Client(token);
}).As<IClient>();
A word of warning - you may run into memory leak trouble.
If the IClient implementation is also IDisposable, Autofac is going to hold onto every IClient created until the lifetime scope is disposed because the container is responsible for creating objects... and disposing them. If your controller is a singleton, that means the Func<IClient> will be resolving from the root lifetime scope (the container itself), which further means you can't dispose the captured IClient instances without disposing the whole application container.
You can disable that with ExternallyOwned but then you also will have to dispose things yourself.
It may be better to unwind things just a little and try to do less in DI, more with your own code. For example, actually create your own client factory that knows when to refresh the token, how to construct and dispose of clients, etc. You may even want to look at stuff like IHttpClientFactory which is specifically meant for stuff like this. Then instead of injecting the client, inject the factory and use the factory to get a client instance as you need it. That is, instead of injecting Func<IClient>, inject IHttpClientFactory or something similar, thus reducing the need to try to force the captive dependency to behave and instead addressing the challenge with a solution possibly more appropriate.

strange behavior of HystrixCommand

The project uses SpringBoot(2.3.4) and SpringCloud(Hoxton.SR8).
There are three classes: BillController, BillService(interface) and BillServiceImpl (implements BillService), BillController calls function getBillList declared in BillService.
In BillServiceImpl, there are two method, one is getBillList, the other is simulateUnstableService, getBillList calls simulateUnstableService, and in simulateUnstableService just a long sleep(2000).
The strange thing is that if I annoate getBillList with HystrixCommand, then it works as I expect. But if I move HystrixCommand to annoate simulateUnstableService, then there is no break which means timeout does not trigger Circuit Breaker.
#Service
public class BillServiceImpl implements BillService {
#Override
// have effact
#HystrixCommand(
commandProperties = {
#HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
}
)
public List<Bill> getBillList(long userId) {
return simulateUnstableService(userId);
}
// no effact
// #HystrixCommand(
// commandProperties = {
// #HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
// }
// )
public List<Bill> simulateUnstableService(long userId) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new ArrayList<>();
}
}
And more, if I just copy simulateUnstableService method content to getBillList, and annoate getBillList with HystrixCommand, the breaker also works.
Why?
Excellent question.
Hystrix uses AOP to wrap the method being called and deliver the Circuit Braking functionality. There is actually an aspect class HystrixCommandAspect.java which defines the around advice used to achieve this.
Now, AOPs don't exactly work if you call a method from within a class. See this answer for more clarity- Spring AOP not working for method call inside another method
When the circuit breaks the fallback method is called. We need to mention fallback method inside the hystrix command. The fallback method has the same signature as the method being annotated by hystrix.
Is simulateUnstableService your fallback method?
#HystrixCommand(fallbackMethod='yourFallbackMethod'
commandProperties = {
#HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
}
)
public List<Bill> getBillList(long userId) {
return simulateUnstableService(userId);
}
Also, it is good practice to add the hystrix command properties inside the application.properties file instead of providing along with the annotation.

Bukkit How to change an int in the config file then be able to change it again without reloading (Custom config file class.))

Okay so I am making a custom feature for my OP-Prison server, one of the things that I need to do is get an integer from the players.yml file, check if it is >= one, if it is take away one, save it and then if it is still above one then they can repeat the action untill it's 0.
The issue comes with the fact that I have to restart the server for the file to change, and even when I do, it will only go down by one integer at a time, before having to reload it again.
GUI Creation code:
Main main = Main.getPlugin(Main.class);
#SuppressWarnings("unused")
private FileControl fc;
#SuppressWarnings("unused")
private FileControl playerfc;
public static String inventoryname = Utils.chat(Main.pl.getFileControl().getConfig().getString("Backpacks.White.InventoryName"));
public List<Player> WhiteOpened = new ArrayList<>();
public static Inventory whiteBackpack(Player player) {
Inventory whiteBackpack = Bukkit.createInventory(null, 27, (inventoryname));
UUID uuid = player.getUniqueId();
whiteBackpack.setItem(10,
new ItemCreator(Material.INK_SACK).setData(8)
.setDisplayname(Utils.chat("&fCommon Packages &8ยป &f&l" + Main.pl.getPlayerFile().getConfig().getInt("Users." + uuid + ".Packages.Common")))
.getItem());
return whiteBackpack;
}
Code for updating the config + item when the Commonpackage is clicked:
#EventHandler
public void whiteBackpackInteract(InventoryClickEvent event) {
Player player = (Player) event.getWhoClicked();
UUID uuid = player.getUniqueId();
ItemStack clicked = event.getCurrentItem();
String title = event.getInventory().getName();
if (title.equals(inventoryname)) {
// Making it so that the item cannot be moved
event.setCancelled(true);
if (clicked != null) {
if (event.getSlot() == 10) {
// Getting the user's common packages section in the config and checking if it is greater than or equal to 1.
if (Main.pl.getPlayerFile().getConfig().getInt("Users." + uuid + ".Packages.Common") >= 1) {
// Saving the user's common package section to 'currentCommon'
Integer currentCommon = Main.pl.getPlayerFile().getConfig().getInt("Users." + uuid + ".Packages.Common");
// Taking away one from 'currentCommon' and saving it to 'newCommon'
Integer newCommon = currentCommon - 1;
// Getting the 'players.yml' file
File file = new File(main.getDataFolder(), "players.yml");
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
// Checking if the current common keys is greater than or equal to 1
if (currentCommon >= 1) {
try {
//Now, Here's where the error lies.
//Gets the player's common package count and sets it to the 'newCommon' count
config.set("Users." + uuid + ".Packages.Common", newCommon);
//Saves the players.yml file
config.save(file);
} catch (IOException e) {
e.printStackTrace();
}
// Updates the inventory they're currently in (Atleast it's meant to...)
player.updateInventory();
// Sends them a message (This is just for testing purposes, making sure it's working.)
player.sendMessage(Utils.chat("&8(&9Vexil&8) &fCommon Package"));
}
}
}
}
}
}
If there is any other code that you need, just ask I'll happily provide it for you.
Right now, you need to restart the server for it to save the data to the file. This should not happen, since you are calling the method config.save(file). The following is simply speculation, but it's the only cause that I think can easily explain what is going on.
In the object that is returned by getPlayerFile().getConfig(), there is likely a variable that stores a FileConfiguration object. That variable houses all the data from the players.yml file. In your whiteBackpackInteract() method, you load the data all over again. You then continue on to write to this NEW FileConfiguration variable, rather than the one that is stored in getPlayerfile().getConfig(). Since you then proceed to save to the file directly, the variables stored in the getPlayerfile().getConfig() is never told that you changed some values around. To fix this, you need to change the following:
config.set("Users." + uuid + ".Packages.Common", newCommon);
config.save(file);
to this:
Main.pl.getPlayerFile().getConfig().set("Users." + uuid + ".Packages.Common", newCommon);
Main.pl.getPlayerFile().getConfig().save(file);
and then delete this line of code:
FileConfiguration config = YamlConfiguration.loadConfiguration(file);
This should solve your problem entirely. If it does not, I would recommend not using your friend's custom config API and instead just use the ones that are built in. Using third party code that you don't properly understand can very often lead to problems such as this.
The following are not the bugs, but are suggestions to help improve your code:
You should be sure to put your comments ABOVE or to the RIGHT over the code they describe. People read from top to bottom, so the comments (before I made the suggested edit to your post) were all below the code they describe.
Typically, you want to try to make sure that if code doesn't need to be run, it isn't. Since the int newCommon is not used until inside that if statement, you should move it in there.
You are using Main.getPlugin();
Now while that doesn't seem like such a bad thing, your getting an unassigned variable, I have no idea how it is working but you're assigning Main to Main. There are 2 proper ways to actually get the main class.
The first, and generally best way, is to use dependency injection.
So basically,
public class Main extends JavaPlugin {
#Override
public void onEnable() {
BackpackListener listener new Backpacklistener(this);
getServer().getPluginManager().registerEvents(listener, this);
}
}
public class BackpackListener implements Listener {
private Main instance;
private BackpackUtil util;
public BackpackListener(Main instance) {
this.instance = instance;
util = new BackpackUtil();
}
#EventHandler
public void onClick(InventoryClickEvent event) {
//code
util.whiteBackpack(instance);
}
public class BackpackUtil {
public Inventory whiteBackpack(Main instance) {
FileConfiguration config = instance.getConfig();
//Do things
instance.saveConfig();
}
}
The next way you can do it is less optimal, and frowned upon, but still an easier option.
public class Main() {
public static Main instance;
#Override
public void onEnable() {
instance = this;
}
}
public class ConfigHelper() {
Main instance = Main.instance;
FileConfiguration config = instance.getConfig();
//Do things
instance.saveConfig();
}
It's good to get out of the habit of using the second method (It's called a singleton), because normally the main class will change, or have multiple instances, etc... but with Spigot there can only be one main instance and one thread.

Class Member becomes undefined

I am quite new to TypeScript and I experience a strange problem at the moment. I create an instance of my main class when the document is ready, using JQuery.
var main: MainApp;
$(document).ready(function () {
main = new MainApp();
});
The simplified MainApp Class:
class MainApp {
// Helper Objects
net: AppNetworking;
urlHelper: UrlHelper;
cat: Category;
// Construction
constructor() {
this.net = new AppNetworking();
this.urlHelper = new UrlHelper();
}
// Ajax Callback with Data needed to initialize the "cat" object
private AjaxCallback(categoryData){
this.cat = new Category(categoryData);
}
// Event Handler for an HTML-Element
// As it would be called anonymously in JS I decided to make it a static function
static onClickSendButton(): void{
// Using some members of the MainApp
var hostUrl: string = main.urlHelper.getQueryStringParam("HostUrl");
if (main.cat.isValidCategory()) {
main.sendCategory();
}
}
sendCategory(): boolean {
// Some logic to send data via AJAX
}
}
The function is being registered to the onClick Event of a Button on construction of the MainApp Class.
$("#btnSendCat").click(MainApp.onClickSendButton);
When the function onClickSendButton() gets called, it produces the error:
Uncaught TypeError: Cannot read property 'isValidCategory' of undefined
When debugging, the urlHelper Instance is defined, but the cat Instance is undefined. As I do not touch the instance cat anywhere in my application, I'm really confused how it is undefined. Also when checking the main variable all members are defined!
Am I doing anything illegal here? Could there be issues with that code?
Completely revised answer. I actually answered with the two most common scenarios for this error, but actually your problem is different.
The usual answers are
Make sure you are referencing .js files, not .ts files
Make sure you are loading scripts in the correct order
In your case, this is not the problem and your code is sufficient to recreate the issue.
I have put together the following test, filling in the blanks - and it works as expected.
app.ts
declare var main: MainApp;
class AppNetworking {
}
class UrlHelper {
getQueryStringParam(input: string) {
console.log('Got here getQueryStringParam');
return input;
}
}
class Category {
isValidCategory() {
console.log('Got here isValidCategory');
return true;
}
}
class MainApp {
// Helper Objects
net: AppNetworking;
urlHelper: UrlHelper;
cat: Category;
// Construction
constructor() {
this.net = new AppNetworking();
this.cat = new Category();
this.urlHelper = new UrlHelper();
}
// Event Handler for an HTML-Element
// As it would be called anonymously in JS I decided to make it a static function
static onClickSendButton(): void{
// Using some members of the MainApp
var hostUrl: string = main.urlHelper.getQueryStringParam("HostUrl");
if (main.cat.isValidCategory()) {
main.sendCategory();
}
}
sendCategory(): boolean {
// Some logic to send data via AJAX
return true;
}
}
index.html snip
<div id="btnSendCat">BTN SEND CAT</div>
<script src="app.js"></script>
<script src="Scripts/jquery-2.1.1.min.js"></script>
<script>
var main;
$(document).ready(function () {
main = new MainApp();
$("#btnSendCat").click(MainApp.onClickSendButton);
});
</script>
The result of running this test is the following output in the console window:
"Got here getQueryStringParam" app.js:10
"Got here isValidCategory" app.js:19
I left some important parts of my App out, I'm sorry. Later in the project I used to reinitialize that Category Object. This re initialization was done in an AJAX-Callback Function. This function runs outside of my Object and this wont be my MainApp Class but the Window. I think it's what you call an anonymous function in JavaScript.
I fixed that issue by taking use of my global main Variable
class MainApp {
// Called anonymous so it should be a static function
private AjaxCallback(categoryData){
// this.cat = new Category(categoryData); ! this will be the Window Instance and not a MainApp Instance
main.cat = new Category(categoryData); // Initialization using the "main" variable
}
}
The call in my onClickSendButton Method to this.cat succeeds now, as this.cat was reinitialized correctly.
This video helped me a lot in my researches: Understanding "this" in TypeScript

EFPocoAdapter -- PopulatePocoEntity has null PocoEntity

I'm trying EF with the EFPocoAdapter for the first time. I have a relatively simple TPH scenario with one table and two types, each inheriting from an abstract base class.
My model validates through EdmGen, and my PocoAdapter.cs and xxxEntities.cs files generate fine as well. (well, actually, there are some namespace problems that I'm currently tweaking by hand until we figure out where to go next.)
When I run a simple test to retrieve data:
using (CINFulfillmentEntities context = new CINFulfillmentEntities())
{
// use context
var alerts = from p in context.Notifications.OfType<Alert>()
select p;
foreach (var alert in alerts)
{
Assert.IsNotNull(alert);
}
}
I get an error in the PocoAdapter class, claiming that PocoEntity is null is the following method inside my base class's adapter:
public override void PopulatePocoEntity(bool enableProxies)
{
base.PopulatePocoEntity(enableProxies);
PocoEntity.Owner = _Owner.CreatePocoStructure();
if (!(PocoEntity is IEntityProxy))
{
}
}
Any ideas from anyone?
So, after a little more debugging, I think this is related to proxies. Inside PocoAdapterBase we have the following method:
protected PocoAdapterBase(TPocoClass pocoObject)
{
_context = ThreadLocalContext.Current;
bool allowProxies = false;
if (_context != null)
{
allowProxies = _context.EnableChangeTrackingUsingProxies;
}
_pocoEntity = pocoObject ?? (TPocoClass)(allowProxies ? CreatePocoEntityProxy() : CreatePocoEntity());
Init();
InitCollections(allowProxies);
RegisterAdapterInContext();
}
The line that sets _pocoEntity calls CreatePocoEntityProxy, which returns null.
More info as I find it.