Is it possible to modify msg.data by assigning a new value to it and forwarding it to the next function call?
For example:
Proxy.sol
fallback() external payable virtual {
_fallback();
}
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
Can you do something in _beforeFallback that changes msg.data and passes it _delegate? Like:
_beforeFallback() internal override {
msg.data = msg.data + 0x1111000000000000000000000000000000001111 //random example
}
Thanks!
Related
I really don't know how to create an object with data from Cassandra without breaking my reactive chain?
I have some private method that is part of the whole reactive chain:
private Mono<SecurityData> createSecurityData(Security securityOfType) {
return jobsProgressRepository
.findByAgentId(securityOfType.getAgentId()) //Flux<JobsProgress>
.collectList() //Mono<List<JobsProgress>>
.flatMap(this::getJobsProgressSummary) //Mono<JobsProgressSummary>
.flatMap(job -> mapToSecurityData(job, securityOfType));
}
and then i want to prepare some object:
private Mono<SecurityData> mapToSecurityData(JobsProgressSummary job, Security security ) {
SecurityData securityData = new SecurityData();
securityData.setAgentId(security.getAgentId());
securityData.setGroupId(security.getGroupId());
securityData.setHostname(getHostname(security)); --> here is the problem!!!
return Mono.just(securityData);
}
And getHostname method:
private String getHostname(Security security) {
String hostname = "";
switch(security.getProductType()){
case VM: hostname = vmRepository
.findByAgentId(security.getAgentId()).blockFirst().getHostname();
case HYPER: hostname = hyperRepository
.findByAgentId(security.getAgentId()).blockFirst().getHostname();
default: ""
}
return hostname;
}
My repos look like:
public interface HostRepository extends ReactiveCassandraRepository<Host, MapId> {
Flux<Host> findByAgentId(UUID agentId);
}
Maybe is my approach wrong? I can't of course use
hostRepository
.findByAgentId(security.getAgentId()).subscribe() // or blockFirst()
because I don't want to break my reactive chain...
How can I solve my problem? Please don't hesitate to give any, even very small tips:)
UPDATE
Here I added the missing body of the method getJobsProgressSummary:
private Mono<JobsProgressSummary> getJobsProgressSummary(List<JobsProgress> jobs) {
JobsProgressSummary jobsProgressSummary = new JobsProgressSummary();
jobs.forEach(
job -> {
if (job.getStatus().toUpperCase(Locale.ROOT).equals(StatusEnum.RUNNING.name())) {
jobsProgressSummary.setRunningJobs(jobsProgressSummary.getRunningJobs() + 1);
} else if (job.getStatus().toUpperCase(Locale.ROOT).equals(StatusEnum.FAILED.name())) {
jobsProgressSummary.setAmountOfErrors(jobsProgressSummary.getAmountOfErrors() + 1);
} else if (isScheduledJob(job.getStartTime())) {
jobsProgressSummary.setScheduledJobs(jobsProgressSummary.getScheduledJobs() + 1);
}
});
Instant lastActivity =
jobs.stream()
.map(JobsProgress::getStartTime)
.map(startTime -> Instant.ofEpochMilli(Long.parseLong(startTime)))
.max(Instant::compareTo)
.orElseGet(null);
jobsProgressSummary.setLastActivity(lastActivity);
return Mono.just(jobsProgressSummary);
}
You need to chain everything together, your code currently is like a mix of imperative and reactive. Also you should never need to call block.
Something like below should work
private Mono<SecurityData> mapToSecurityData(JobsProgressSummary job, Security security ) {
//Try to get hostname first, then process result
return getHostname(security)
//Map it. Probz should use builder or all args constructor to reduce code here
.map(hostname -> {
SecurityData securityData = new SecurityData();
securityData.setAgentId(security.getAgentId());
securityData.setGroupId(security.getGroupId());
securityData.setHostname(hostname);
return securityData;
});
}
private Mono<String> getHostname(Security security) {
Mono<String> hostname = Mono.empty();
switch(security.getProductType()){
//Also assuming hostname is a field in Security
//just change Security to class name if not
case VM: hostname = vmRepository.findByAgentId(security.getAgentId())
.next()
.map(Security::getHostname);
case HYPER: hostname = hyperRepository.findByAgentId(security.getAgentId())
.next()
.map(Security::getHostname);
}
return hostname;
}
I have an account service and a product service communicating. When a request comes from a user to purchase a product (I did not include the user service, it is working fine and not the issue), the product service checks to see if there are enough funds in the account, and if there is it updates the balances. The following code works fine:
#GetMapping("/account/{userId}/product/{productId}")
public Mono<ResponseEntity<Product>> checkAccount(#PathVariable("userId") int userId,#PathVariable("productId") int productId){
Mono<Account> account = webClientBuilder.build().get().uri("http://account-service/user/accounts/{userId}/",userId)
.retrieve().bodyToMono(Account.class);
Mono<Product> product = this.ps.findById(productId);
Mono<Boolean> result = account.zipWith(product,this::isAccountBalanceGreater);
Mono<ResponseEntity<Product>> p = result.zipWith(product,this::getResponse);
return p;
}
public boolean isAccountBalanceGreater(Account acc, Product prd) {
return(acc.getBalance()>=prd.getPrice()):
}
public ResponseEntity<Product> getResponse(boolean result,Product prod){
if(result) {
return ResponseEntity.accepted().body(prod);
}else {
return ResponseEntity.badRequest().body(prod);
}
}
My put method in the account service also works fine:
#PutMapping("/account/update/{accountId}")
public Mono<ResponseEntity<Account>> updateAccount(#PathVariable("accountId") int accountId, #RequestBody Account account) {
return as.findById(accountId)
.flatMap(oldAcc->{
oldAcc.setAccountId(account.getAccountId());
oldAcc.setAccountId(account.getAccountId());
oldAcc.setOwner(account.getOwner());
oldAcc.setPin(account.getPin());
oldAcc.setBalance(account.getBalance());
oldAcc.setUserId(account.getUserId());
return ar.save(oldAcc);
}).map(a -> ResponseEntity.ok(a))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
Now I want to be able to update the balances, I have tried this in the isAccountBalancerGreater method:
public boolean isAccountBalanceGreater(Account acc, Product prd) {
if(acc.getBalance() >= prd.getPrice()) {
double newBuyerBalance =acc.getBalance() - prd.getPrice();
Account newOwnerAcc = new Account(acc.getAccountId(),acc.getOwner(),acc.getPin(),newBuyerBalance,acc.getUserId());
this.ps.removeProduct(prd.getProductId());
webClientBuilder.build().put().uri("http://account-service/account/update/{accountId}",acc.getAccountId()).body(newOwnerAcc,Account.class).exchange();
return true;
}
return false;
}
However this does not work, not error just nothing updates.
My test case works when I run the same code with a test account. I'm not sure why this is not executing. Any suggestions?
you have to think of reactive code as event chains or callbacks. So you need to respond to what you want something to do, after some other thing has been completed.
return webClientBuilder.build()
.put().uri("http://account-service/account/update/{accountId}",
acc.getAccountId())
.body(newOwnerAcc,Account.class)
.exchange()
.thenReturn(true); // if you really need to return a boolean
return a boolean is usually not semantically correct in a reactive world. Its very common to try to avoid if-else statements
One way is to return a Mono<Void> to mark that something has been completed, and trigger something chained onto it.
public Mono<Void> isAccountBalanceGreater(Account acc, Product prd) {
return webclient.put()
.uri( ... )
.retrieve()
.bodyToMono(Void.class)
.doOnError( // handle error )
}
// How to call for example
isAccountBalanceGreater(foo, bar)
.doOnSuccess( ... )
.doOnError( ... )
I'm trying to set a user idle timeout here. Everything seems to work...except the clearTimeout function. Events work, setTimeout works but no matter what I do, as soon as I set it up first time, can't stop it. Method gets called from the onBeforeRendering function of my main controller. No visible error from the debugger. Any help?
setTimeOut: function () {
var self = this;
var timeOut = function userTimeout() {
jQuery.sap.log.error("TIMEOUT");
try {
if (self.getModel("Global").getProperty("/RecordUnlocked") === true) {
self._unlockRecord();
}
} catch(e) {
jQuery.sap.log.error("TIMEOUT");
};
try {
var navHistory = self.getView().getModel("Global").getProperty("/NavHistory");
history.go(navHistory);
} catch(e) {
jQuery.sap.log.error("TIMEOUT");
}
/* MessageBox.show(self.getModel("i18n").getResourceBundle().getText("timeOut"), {
onClose: function(oAction) {*/
};
function reset() {
clearTimeout(timeOut);
setTimeout(timeOut, 20000);
}
document.onmousemove = reset;
document.onkeypress = reset;
}
window.clearTimeout clears the returning value of window.setTimeout, not the function you're executing in the timeout itself.
The timeout variable you have there is not actually the result of the setTimeout function but a function you defined.
Usually, it's something like
var myTimeoutFunction = _ => console.log('hi');
var myTimeout = window.setTimeout(myTimeoutFunction, 20000);
window.clearTimeout(myTimeout);
As a word of warning, your own function is also called setTimeout. Which one is executed in the callback of the mouse- and key events depends on the current context. I guess you're lucky here because the event will run in the window context but it could be confusing if you ever bind the function or something
I am trying to implement skill based matchmaking using Photon in Unity. It seems
I got most of this code from the documentation and it works but not well.
The problem is that you can't use JoinOrCreate() with the sql lobby type so my logic here is try and find a room, if it fails create one.
void init()
{
_client = Game.Context.GetComponent<SocketConnectionManager>().client;
joinRoom();
}
public void joinRoom()
{
TypedLobby sqlLobby = new TypedLobby("skillLobby", LobbyType.SqlLobby);
string sqlLobbyFilter = "C0 BETWEEN 100 AND 200";
_client.OpJoinRandomRoom(null, MatchMaker.MaxPlayers, MatchmakingMode.FillRoom, sqlLobby, sqlLobbyFilter);
}
public void createRoom()
{
RoomOptions o = new RoomOptions();
o.MaxPlayers = MatchMaker.MaxPlayers;
o.CustomRoomProperties = new Hashtable() { { "C0", Game.Me.getInt("trophies") } };
o.CustomRoomPropertiesForLobby = new string[] { "C0" }; // this makes "C0" available in the lobby
TypedLobby sqlLobby = new TypedLobby("skillLobby", LobbyType.SqlLobby);
_client.OpCreateRoom("", o, sqlLobby);
}
private void onEvent(EventData obj)
{
if (_client.CurrentRoom != null)
{
if (_client.CurrentRoom.PlayerCount >= _client.CurrentRoom.MaxPlayers)
{
// sweet I am good to go.
}
}
else
{
createRoom();
}
}
The problem is this is pretty unreliable. Say two players try to find a game at the same time they will both search fail and then both create. Now I have two players sitting in empty rooms instead of playing each other.
Any ideas on a better system?
Thanks all.
Thank you for choosing Photon!
First of all, there are few things that you should understand about Photon:
you can't use JoinOrCreate() with the sql lobby type
This is not correct.
Where did you read such thing?
Did you test this yourself? What did you test exactly?
onEvent (LoadBalancingClient.OnEventAction) callback cannot be used to be notified of a failed join random room operation. Instead, you should make use of the LoadBalancingClient.OnOpResponseAction callback, as follows:
private void OnOpResponse(OperationResponse operationResponse)
{
switch (operationResponse.Code)
{
case OperationCode.JoinRandomGame:
if (operationResponse.ReturnCode == ErrorCode.NoMatchFound)
{
createRoom();
}
break;
}
}
To detect a join event inside a room (local or remote player entered a room):
private void onEvent(EventData eventData)
{
switch (eventData.Code)
{
case EventCode.Join:
int actorNr = (int)eventData[ParameterCode.ActorNr];
PhotonPlayer originatingPlayer = this.GetPlayerWithId(actorNr);
if (originatingPlayer.IsLocal)
{
}
else
{
}
break;
}
}
To answer your question:
Say two players try to find a game at the same time they will both
search fail and then both create.
Any ideas on a better system?
No.
This issue happens only during the development phase where you use a few clients to run some tests. Once you have enough user base you won't notice this issue.
I am updating large amounts of data using ServiceStack's OrmLite with a connection to PostgreSQL, however, I am getting a large amount of timeouts.
Sample Code:
public class AccountService : Service
{
public object Any(ImportAccounts request)
{
var sourceAccountService = this.ResolveService<SourceAccountService();
var sourceAccounts = (GetSourceAccountResponse)sourceAccountService.Get(new GetSourceAccounts());
foreach (var a in sourceAccounts)
{
Db.Save(a.ConvertTo<Account>());
}
}
}
The Source Account service, which sits in the same project & accesses the same Db.
public class SourceAccountService : Service
{
public object Get(GetSourceAccounts request)
{
return new GetSourceAccountsResponse { Result = Db.Select<SourceAccounts>().ToList() };
}
}
Questions,
Should I be expecting large amount of timeouts considering the above set up?
is it better to be using using (IDbConnection db = DbFactory.OpenDbConnection()) instead of Db?
If you're resolving and executing a Service you should do it in a using statement so its open Db connection and
other resources are properly disposed of:
using (var service = this.ResolveService<SourceAccountService())
{
var sourceAccounts = service.Get(new GetSourceAccounts());
foreach (var a in sourceAccounts)
{
Db.Save(a.ConvertTo<Account>());
}
}
If you're executing other Services it's better to specify the Return type on the Service for added type safety
and reduced boiler plate at each call site, e.g:
public class SourceAccountService : Service
{
public GetSourceAccountsResponse Get(GetSourceAccounts request)
{
return new GetSourceAccountsResponse {
Result = Db.Select<SourceAccounts>()
};
}
}
Note: Db.Select<T> returns a List so .ToList() is unnecessary,
Another alternative for executing a Service instead of ResolveService<T> is to use:
var sourceAccounts = (GetSourceAccountsResponse)base.ExecuteRequest(new GetSourceAccounts());
Which is same above and executes the Service within a using {}.