Ajax.post --> dom.fetch - ajax

I'm trying to use the dom.fetch (or dom.Fetch.fetch) api instead of Ajax.post and have a few problems:
Is this a correct translation from ajax to fetch?
Ajax.post(
url = "http://localhost:8080/ajax/myMethod",
data = byteBuffer2typedArray(Pickle.intoBytes(req.payload)),
responseType = "arraybuffer",
headers = Map("Content-Type" -> "application/octet-stream"),
)
dom.fetch(
"http://localhost:8080/fetch/myMethod",
new RequestInit {
method = HttpMethod.POST
body = byteBuffer2typedArray(Pickle.intoBytes(req.payload))
headers = new Headers {
js.Array(
js.Array("Content-Type", "application/octet-stream")
)
}
}
)
A "ReferenceError: fetch is not defined" is thrown on the js side though, same if replacing with dom.Fetch.fetch.
My setup:
Fresh jsdom 19.0.0 with
npm init private
npm install jsdom
project/plugins.sbt
libraryDependencies += "org.scala-js" %% "scalajs-env-jsdom-nodejs" % "1.1.0"
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.8.0")
build.sbt (in js project)
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.0.0"
jsEnv := new JSDOMNodeJSEnv(JSDOMNodeJSEnv.Config()
.withArgs(List("--dns-result-order=ipv4first")))
Thought that the jsEnv workaround was not needed on Scala.js 1.8 (see https://github.com/scala-js/scala-js-js-envs/issues/12#issuecomment-958925883). But it is still needed when I run the ajax version. With the workaround, my ajax version works fine, so it seems that my node installation is fine.

The fetch API is only available by-default in browser environments, and not in Node. node-fetch is also not pulled in (or at least not re-exported) by jsdom, so fetch is not available with the current package/environment setup.
Possible solutions:
Set the ScalaJS side up in such a way that it would call node-fetch on NodeJS and fetch on browser
Use XMLHttpRequest which is available on both platforms
(Please see the #scala-js channel in the Scala Discord for a related conversation).

Got help on the scala-js channel on Discord from #Aly here and #armanbilge here who pointed out that:
fetch is not available by default in Node.js or JSDOM, only in browsers.
scala-js-dom provides typesafe access to browser APIs, not Node.js APIs.
The distinction between browser API and Node API wasn't clear for me before, although it is well described in step 6 of the scala-js tutorial.
So, dom.fetch of the scala-js-dom API works when running a js program in a browser, but not if running a test that uses the Node jsEnv(ironment)! To fetch in a test one would have to npm install node-fetch and use node-fetch, maybe by making a facade with scala-js.
Since I want my code to work for both browser (scala-js-dom) and test (Node.js), I ended up falling back to simply using the Ajax.post implementation with XMLHttpRequest:
case class PostException(xhr: dom.XMLHttpRequest) extends Exception {
def isTimeout: Boolean = xhr.status == 0 && xhr.readyState == 4
}
val url = s"http://$interface:$port/ajax/" + slothReq.path.mkString("/")
val byteBuffer = Pickle.intoBytes(slothReq.payload)
val requestData = byteBuffer.typedArray().subarray(byteBuffer.position, byteBuffer.limit)
val req = new dom.XMLHttpRequest()
val promise = Promise[dom.XMLHttpRequest]()
req.onreadystatechange = { (e: dom.Event) =>
if (req.readyState == 4) {
if ((req.status >= 200 && req.status < 300) || req.status == 304)
promise.success(req)
else
promise.failure(PostException(req))
}
}
req.open("POST", url) // (I only need to POST)
req.responseType = "arraybuffer"
req.timeout = 0
req.withCredentials = false
req.setRequestHeader("Content-Type", "application/octet-stream")
req.send(requestData)
promise.future.recover {
case PostException(xhr) =>
val msg = xhr.status match {
case 0 => "Ajax call failed: server not responding."
case n => s"Ajax call failed: XMLHttpRequest.status = $n."
}
println(msg)
xhr
}.flatMap { req =>
val raw = req.response.asInstanceOf[ArrayBuffer]
val dataBytes = TypedArrayBuffer.wrap(raw.slice(1))
Future.successful(dataBytes)
}

Related

vuepress build docs get ReferenceError: pageMeta is not defined?

vuepress dev docs is ok, but vuepress build docs get the following error, why?
...
...
✔ Client
Compiled successfully in 22.59s
✔ Server
Compiled successfully in 15.41s
wait Rendering static HTML...
error Error rendering /404.html: false
undefined
...
...
ReferenceError: pageMeta is not defined
...
...
tl;dr You need to downgrade vue-router which is installed as part of vuepress to match ~3.1.3.
I've basically encountered the same error when trying to implement some VuePress theme.
AFAICT the pageMeta is related to VuePress rendering pages on server-side (SSR). It's used in a template using triple curly braces and there are parts of vuepress-generated code assigning data for this markup to be replaced with properly. Since I didn't touch any SSR-related stuff in VuePress I'm quite sure I haven't done anything causing this particular issue explicitly.
So I've tried to disable parts of my code to locate the fragment which is causing this misbehaviour. It turns out the obvious culprit is vue-router.
I'm applying a navigation guard on vue-router instance exposed in enhanceApp.js of VuePress. Inside that guard I put code complying with existing documentation for vue-router. Essentially, I am redirecting some requests due to optionally existing redirection tables or frontmatter information.
In vuepress dev this code is working, but generating errors in browser console. Those errors are about an unhandled promise rejection due to aborting initially requested routing transition in favour of starting another one which seems an eligible intention on using vue-router.
does not work:
export default function( context ) {
const { router, siteData: { pages, themeConfig = {} } } = context;
router.beforeEach( handleRedirects );
function handleRedirects( to, from, next ) {
const numPages = pages.length;
for ( let i = 0; i < numPages; i++ ) {
const { path, frontmatter } = pages[i];
if ( path === to.path && frontmatter.redirect ) {
if ( from.path === frontmatter.redirect ) {
next( false );
} else {
next( frontmatter.redirect );
}
return;
}
}
const redirections = themeConfig.redirect || {};
if ( redirections.hasOwnProperty( to.path ) ) {
next( redirections[to.path] );
return;
}
next();
}
}
does work:
export default function( context ) {
const { router, siteData: { pages, themeConfig = {} } } = context;
router.beforeEach( handleRedirects );
function handleRedirects( to, from, next ) {
const numPages = pages.length;
for ( let i = 0; i < numPages; i++ ) {
const { path, frontmatter } = pages[i];
if ( path === to.path && frontmatter.redirect ) {
if ( from.path === frontmatter.redirect ) {
next( false );
} else {
next(); // <--- omitting passed target
}
return;
}
}
const redirections = themeConfig.redirect || {};
if ( redirections.hasOwnProperty( to.path ) ) {
next(); // <--- omitting passed target
return;
}
next();
}
}
Just to be clear: The latter one makes vuepress build succeed, but the result isn't functional with regards to properly handling redirects.
IMHO the issue is with vue-router for rejecting some promise I didn't start here. One might claim it is with vuepress for failing to adopt a change in API by handling rejected routing transitions properly. But this is also true for SSR (look at third code example given there).
As a solution, you could try downgrading vue-router to versions prior to 3.2.0. In my case, vuepress is properly asking for version ^3.1.3. However, due to semantic versioning, this selector is covering latest 3.4.3 as well.
Thus concluding, there is a breaking change in vue-router, which has been introduced with minor release version 3.2.0. Because of that vue-router isn't complying with semantic versioning.
IMHO, this change of behaviour isn't quite eligible at all for code using vue-router should not have to care about how routing is proceeding unless it leads to some valid target. Thus, code asking to switch route shouldn't cause a rejection that must be handled. This feedback might be optional, but right now it is sort of mandatory.

groovy command curl on windows Jenkins

I have a groovy script that work on Linux Jenkins
import groovy.json.JsonSlurper
try {
List<String> artifacts = new ArrayList<String>()
//jira get summery for list by issue type story and label demo and project 11411
def artifactsUrl = 'https://companyname.atlassian.net/rest/api/2/search?jql=project=11411%20and%20issuetype%20in%20(Story)%20and%20labels%20in%20(demo)+&fields=summary' ;
def artifactsObjectRaw = ["curl", "-u", "someusername#xxxx.com:tokenkey" ,"-X" ,"GET", "-H", "Content-Type: application/json", "-H", "accept: application/json","-K", "--url","${artifactsUrl}"].execute().text;
def parser = new JsonSlurper();
def json = parser.parseText(artifactsObjectRaw );
//insert all result into list
for(item in json.issues){
artifacts.add( item.fields.summary);
}
//return list to extended result
return artifacts ;
}catch (Exception e) {
println "There was a problem fetching the artifacts " + e.message;
}
This script return all the names from Jira jobs by the API ,
But when I tried to run this groovy on Windows Jenkins the script will not work because windows do not have the command curl
def artifactsObjectRaw = ["curl", "-u","someusername#xxxx.com:tokenkey" ,"-X" ,"GET", "-H", "Content-Type: application/json", "-H", "accept: application/json","-K","--url","${artifactsUrl}"].execute().text;
how should I preform this command?
The following code:
import groovy.json.JsonSlurper
try {
def baseUrl = 'https://companyname.atlassian.net'
def artifactsUrl = "${baseUrl}/rest/api/2/search?jql=project=MYPROJECT&fields=summary"
def auth = "someusername#somewhere.com:tokenkey".bytes.encodeBase64()
def headers = ['Content-Type': "application/json",
'Authorization': "Basic ${auth}"]
def response = artifactsUrl.toURL().getText(requestProperties: headers)
def json = new JsonSlurper().parseText(response)
// the below will implicitly return a list of summaries, no
// need to define an 'artifacts' list beforehand
def artifacts = json.issues.collect { issue -> issue.fields.summary }
} catch (Exception e) {
e.printStackTrace()
}
is pure groovy, i.e. no need for curl. It gets the items from the jira instance and returns a List<String> of summaries. Since we don't want any external dependencies like HttpBuidler (as you are doing this from jenkins) we have to manually do the basic auth encoding.
Script tested (the connecting and getting json part, did not test the extraction of summary fields) with:
Groovy Version: 2.4.15 JVM: 1.8.0_201 Vendor: Oracle Corporation OS: Linux
against an atlassian on demand cloud instance.
I removed your jql query as it didn't work for me but you should be able to add it back as needed.
Install curl and set the path in environment variable of windows.
Please follow the link to download curl on windows.
I would consider using HTTP request plugin when making HTTP Requests.
Since you are using a plugin, it does not matter if you are running in Windows or .
Linux as your Jenkins Host

Geocoding requests to HERE API randomly fails

I am trying to geocode addresses with HERE API. I am not free plan. I try following code (Spring Boot in Kotlin):
override fun geocode(address: Address): Coordinate? {
val uriString = UriComponentsBuilder
.fromHttpUrl(endpoint)
.queryParam("app_id", appId)
.queryParam("app_code", appCode)
.queryParam("searchtext", addressToSearchText(address))
.toUriString()
logger.info("Geocode requested with url {}", uriString)
val response = restTemplate.getForEntity(uriString, String::class.java)
return response.body?.let {
Klaxon().parse<GeocodeResponse>(it)
}?.let {
it.Response.View.firstOrNull()?.Result?.firstOrNull()
}?.let {
Coordinate(
latitude = it.Location.DisplayPosition.Latitude,
longitude = it.Location.DisplayPosition.Longitude
)
}.also {
if (it == null) {
logger.warn("Geocode failed: {}", response.body)
}
}
}
It turned out that when I call this method many times in a row, some requests returns empty responses, like this:
{
"Response":{
"MetaInfo":{
"Timestamp":"2019-04-18T11:33:17.756+0000"
},
"View":[
]
}
}
I could not figure out any rule why some requests fail. It seems to be just random.
However, when I try to call same URLs with curl of in my browser, everything works just fine.
I guess there is some limit for amount requests per seconds, but I could not find anything in HERE documentation.
Does anyone have an idea about the limit? Or may it be something else?
Actually, there was a problem with my code. Requests were failing for addresses having "special" symbols like ü and ö. The problem was with building request URL
val uriString = UriComponentsBuilder
.fromHttpUrl(endpoint)
.queryParam("app_id", appId)
.queryParam("app_code", appCode)
.queryParam("searchtext", addressQueryParam(address))
.build(false) // <= this was missed
.toUriString()

Xcode : realm thread issue

i am new to IOS development and i recently tried realm
the problem is that, i have to get the urls from a json file and then i put those urls in realm as an object ...and whenever i start my app again the URL variable would get the respected url from realm...
like this:
getUrls()
let realm = try! Realm()
// Query Realm for all dogs less than 2 years old
let urls = realm.objects(UrlCollector.self).first
let sss = realm.objects(UrlCollector.self)
print("no of objects in did load \(sss.count)")
loginUrl = urls!.login
print("login url inside didload \(loginUrl)")
but the problem is getUrls method...it updates the urls using almofire
getUrls method:
Alamofire.request("<<<myurl>>>", method: .post, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(data)
let data = JSON(data)
for item in data["result"].arrayValue {
let url = UrlCollector()
url.login = "\(self.server)\(item["login"].stringValue)"
print(url.login)
url.changePassword = "\(self.server)\(item["changePassword"].stringValue)"
print(url.changePassword)
url.phoneNumberVerify = "\(self.server)\(item["phoneNumberVerify"].stringValue)"
print(url.phoneNumberVerify)
url.sessionCheck = "\(self.server)\(item["sessionCheck"].stringValue)"
print(url.sessionCheck)
// Get the default Realm
let realm = try! Realm()
var urls = realm.objects(UrlCollector.self)
// Persist your data easily
try! realm.write {
realm.delete(urls)
realm.add(url)
}
// Query Realm for all dogs less than 2 years old
urls = realm.objects(UrlCollector.self)
print(urls.count)
}
}
break
case .failure(_):
print("Error message:\(response.result.error)")
break
}
}
}
this code runs on did load
my log:
no of objects in did load 1
login url inside didload
{
result = (
{
changePassword = "/iust_app/android/passwordChange.php";
login = "/iust_app/android/login.php";
phoneNumberVerify = "/iust_app/android/onNumberVerification.php";
sessionCheck = "/iust_app/android/sessionCheck.php";
}
);
}
/iust_app/android/login.php
/iust_app/android/passwordChange.php
/iust_app/android/onNumberVerification.php
/iust_app/android/sessionCheck.php
1
print("no of objects in did load \(sss.count)")
loginUrl = urls!.login
print("login url inside didload \(loginUrl)")
as you can see these runs before the request...Please read my log lines to understand
All network requests are executed asynchronously. If you want your code to be executed after you get a response from the server put it into the completion handler of this request.

Akka HTTP WebSocket client equivalent of this node.js

I have some user documentation that expresses how to use a websocket with this node snippet:
var socket = io(“HOST:PORT”);
socket.on('request-server', function() {
socket.emit('server-type', 'red')
});
What would the equivalent client code be in Akka HTTP?
I have derived the following from the example in the Akka documentation. It isn't quite what I'd like to write, because
I think I need to connect and wait for the request-server event before sending any events & I don't know how to do that
I don't know how to format the TextMessages in the Source to be equivalent to `socket.emit('server-type', 'red').
It only prints "closed"
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
import system.dispatcher
val incoming: Sink[Message, Future[Done]] = Sink.foreach[Message] {
case message: TextMessage.Strict => println(message.text)
case z => println(z)
}
val outgoing = Source(List(TextMessage("'server-type': 'red'")))
val webSocketFlow = Http().webSocketClientFlow(
WebSocketRequest("ws://localhost:3000/socket.io"))
val (upgradeResponse, closed) =
outgoing
.viaMat(webSocketFlow)(Keep.right)
.toMat(incoming)(Keep.both)
.run()
val connected = upgradeResponse.flatMap { upgrade =>
if (upgrade.response.status == StatusCodes.SwitchingProtocols) {
Future.successful(Done)
} else {
throw new RuntimeException(s"Connection failed: ${upgrade.response.status}")
}
}
connected.onComplete(println)
closed.foreach(_ => println("closed"))
What is the Akka client equivalent to the given socket.io code?
Your connection is getting closed immediately after sending message "outgoing".
Check out Half-Closed Websockets here http://doc.akka.io/docs/akka-http/10.0.0/scala/http/client-side/websocket-support.html#half-closed-websockets

Resources