Is there a possibility on Typescript to create a multithread where each thread calls an hook who asks to an external local Kotlin's library to run a HttpURLConnection request?
I mean, like having on TS an array of IDs and for each ID, instantiate a Thread which runs an hook to ask the Kotlin library to execute a HttpURLConnection for that ID and get back as promise the result of that HttpURLConnection....
#Possibility of Typescript multithread querying an external local Kotlin's library?
48 messages · Page 1 of 1 (latest)
seems like you have a very specific implementation in mind, but what's the big picture? what are you trying to do?
i don't know what "create a multithread" means, but you probably don't need threads at all. normal Promise-based code should be sufficient to make the requests happen concurrently
@digital pendant first thank you for your answer.... my goal would be having an array of IDs (which are some custom devices to query) and at Typescript side , while querying each one with a HttpURLConnection in parallel, get the informations back and show them with a object in a FlatList .... I was thinking about threads so supposing to have 10 IDs I would query all them in parallel and get back informations to cut waiting time.....
by "big picture" i meant zooming out even further. you're trying to write a program that makes HTTP requests, to do what exactly?
what kind of "custom devices"?
@digital pendant let's assume ID[2] in the array contains 122 , so I 'm gonna query HttpURLConnection("https://192.168.3.122&oarameters....") which is a custom device that contains an internal website that's listening and answering with informations I have to show...
why do you need to involve this Kotlin library? is there a reason you couldn't make the HTTP requests directly from your TypeScript code?
I have this Kotlin local library because I used it to get know the mask of the mobile IP (using NetworkInterface Kotlin's library) which is connected to a router where is connected that 192.168.3.122 custom device... so I thought maybe if it is not possible to do multiple threads in Typescript then let Kotlin doing that with ExecutorService + HttpURLConnection....
JavaScript (and therefore TypeScript) have async I/O built in. you don't need threads to make concurrent HTTP requests
@digital pendant you mean I can query parallel each of those 10 custom devices directly with Typescript asynchronously , right?
here's how you would make a bunch of concurrent requests directly:
const responses = await Promise.all([
fetch("https://192.168.3.120...."),
fetch("https://192.168.3.121...."),
fetch("https://192.168.3.122...."),
fetch("https://192.168.3.123...."),
// etc
])
yes
is this code going to be running in a web browser?
that .fetch is similar to Java&Kotlin's HttpURLConnection?
no, React Native's app
yeah, same general idea
ah, that makes a lot more sense. this is the kind of information i was looking for when i asked you about the "big picture"
i don't know if/how react native implements fetch, but it probably just uses the same HTTP stack as native Java/Kotlin under the hood
but your life will be simpler if you can keep all the code in TypeScript rather than trying to communicate across languages
read this i guess: https://reactnative.dev/docs/network
Okay! I'll take a look at that link right now! Thanks for now @digital pendant !
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises could also be a good read if you need to learn about Promises/async/await
I'll read this one too, thanks again for now @digital pendant ! 😊
hello @digital pendant , sorry if I pick again this thread...but referring to your answer about multiple fetchs , in Java I use to run 26 ExecutorService threads where inside each of ExecutorService I call 11 Runnable threads so in this way I have parallel threads to improve performance on querying SocketAddress devices.... in Typescript , should be improved doing like the same, for example having 255 fetch() total so making 15 separate promises where running 17 fetch() in each promise OR is it the same performance if I'd do like PromiseAll as like as in your sample and , inside each them using a for (i=1;i<=255;i++) { fetch(ip+"."+i,....) .... } ? Thanks in advance
can you show me some example code (pseudocode is fine) for what you're imagining here?
having 255
fetch()total so making 15 separate promises where running 17fetch()in each promise
the most important part being how those promises would be executed/awaited
for your other example too, for (…) { fetch(…) } is going to spawn all of those promises and then forget about them (they'll run concurrently) while for (…) { await fetch(…) } is going to wait for each promise to complete before starting the next fetch
i also don't understand why you would want multiple ExecutorServices with your Java version, but my Java is pretty rusty so maybe there's something i'm forgetting
In Java, using an ExecutorService , I am running concurrently his work with one network because I could be connected simultaneously on both networks, WIFI and Hotspot which is possible with some mobile phones,... like executorservicethread.execute ( new pollingNetworkThread(....) ) where inside pollingNetworkThread I pass the mask of wifi network for example like 192.168.3. where it would be cicled inside for each IP calling in a thread first a LOGIN so if successful and obtaining the session_id, then I call another API to same IP as **CONFIGURATION **and if I get result, then another API as **STATUS **to obtain informations of device as json... and my idea was to put all informations to a structure which would be automatically shown as template in a FlatList.... got what I mean sort of?..
On typescript I was starting with something like :
const result: string[] = jsonConnections.flatMap(f => f.Address !== null ? f.Address.substring(0, f.Address.lastIndexOf(".")) : []); // where I get the network which is active and obtaining the mask like 192.168.3.
result.forEach(element => {
let th_Counter = 1
Promise.all(
let urls : string[]
for (i=th_Counter;i<th_Counter+17;i++)
urls.push(element+i.toString()
urls.map(u => Promise.all( useGetData(LOGIN, u, .... ) )
.then(response => (
if ( isJson(response) ) {
Promise.all ( useGetData(CONFIGURATION, u, .... ) )
.then( response => (
if (isJson(response) ) {
completeDataSingleDevice(response)
Promise.all( useGetData(STATUS, u, ....) )
.then( response => (
if ( isJson(response) ) {
completeDataSingleDevice(response)
}
)
}
)
}
)
)
th_Counter=+15
})
something like that where useGetData() would be an export function useGetData where I compose the URL to use inside a fetch where I query that device:
const response = await fetch(urlCommand, {
method: "GET",
headers: { "Content-Type": "application/json" }
});
const json = await response.json()
setData(json)
maybe it's not the right way to make concurrently?...
sorry but i'm having trouble understanding your writing style. maybe there's a language barrier? it might help if you could use more separate sentences
here's what i think your use case is:
- you have a list of IP addresses
- separately for each of those IP addresses, you want to:
- log in
- fetch configuration
- fetch status
- you want to collect all of the responses across all IP addresses into a single flat array
questions:
- do i have the basic use case right?
- how do
LOGIN,CONFIGURATION, andSTATUSdepend on eachother? for example, do you have to include thesession_idyou get back fromLOGINin theCONFIGURATIONrequest?
Hello @digital pendant ... the code I wrote was not precise for sure and I surely missed something or have to rewrite better...
Anyway yes , my goal is : once I obtain the mask of enabled and connected networks like WIFI and/or HOTSPOT/ROUTE (how it is called anyway) like *192.168.3. * with :
const result: string[] = jsonConnections.flatMap(f => f.Address !== null ? f.Address.substring(0, f.Address.lastIndexOf(".")) : []);
and for each network , doing a polling to all IP between 1 and 255 and if at least one logs in (CommandTypes.LOGIN) so having initialized in a .d.ts file an array of elements based to an interface already , I'd start to prepare a single element with Partial<> to store some data and , yes, I get the session_id from the LOGIN, which I use in next two fetchs because are two different kind of API..
I was trying to rewrite the code using Promise.all() so in case of success then initialize a new single element with partial data to be available for next API call where I need session_id... so I was starting to rewrite as :
result.forEach(element => {
let urls : string[] = []
let currentUrl : string = ""
for (let i=1;i<255;i++) {
urls.push(element+i.toString().toString())
}
Promise.all(urls.map(u =>
useGetData(CommandTypes.LOGIN, u,username, password )))
.then(responses => {
responses.map(r => {
if (r.commandDone) {
// Login success
const single: [Partial<ISingleType>] = [{
IPMacAddress: u.toString(),
SessionID: JSON.parse(r.jsonData).filter(el => el.include("session_id").toString())
}]
ElementsList.push(Single);
useGetData(CommandTypes.GETCONFIGURATION,u, Object.values(conf_codes).join(',').toString(), single[0]?.SessionID?.toString())
}
})
})
})
but at the moment I am tryng to understand how to pass the current url , u, inside response and reuse the current element values ...on the other hand I assume using Promise.all is like doing a for(...) { fetch() } , right?...
on the other hand I assume using
Promise.allis like doing afor(...) { fetch() }, right?
not really, though i'm not sure how literally to take the analogy you're making there
let's forget about everything leading up to building urls since that's irrelevant
you have urls, which as far as i can tell is an array full of IP addresses, right? edit: actually i guess you have a separate array of IP addresses per element in result, but i'm not sure why. i suspect you could build one single list of IP addresses by combining stuff from all elements of result
if i understand correctly the CONFIGURATION call does need to happen sequentially after LOGIN because it requires session_id, but i'm not sure how STATUS fits in. can you directly answer the specific questions i asked up here? that will help me help you
if that result variable will have for example 192.168.0. for Wifi and 192.168.170. for Hotspot/Router , then with result.forEach I am going to fill urls with a for () so, yes I'll have like: [192.168.01, 192.168.0.2, ... , 192.168.0.255 , 192.168.170.1 , 192.168.170.2 , ... , 192.168.170.255] and first I have to do a LOGIN to get the session_id which is needed to call both CONFIGURATION and STATUS (they differ just about action2 parameter, GetConfiguration or GetStatus, in URL I compose inside export function useGetData(....) , because there I'd manage also a possible AbortController like if connection goes away...
okay, so if i understand correctly you have two opportunities to do things concurrently:
- you can do all handling for each individual IP address concurrently because they don't depend on eachother at all
- for each IP address, you can do the
CONFIGURATIONandSTATUSrequests concurrently because they don't depend on eachother (but both depend onLOGIN, so that needs to happen first)
does that sound right?
in addition to answering that question ☝️, can you also show me the type signature of useGetData please?
HI @digital pendant , yes you're right about calling all IPs concurrently... I guess just calling a Promise.all would all inside for each IP in the urls array and getting filled back the interface structure for each IP , practically a var elementsList : ISingleElementType[] = [] declared globally in a .d.ts file , which would be used in a FlatList to show all elements from a component template... that is my idea...
About useGetData I was thinking something like that:
export function useGetData (
commandType:CommandTypes,
ip: string,
...params: string[]
) {
const [currentIp, setCurrentIP] = useState<string>("") // so I can pass the current ip to the response after LOGIN to call GETCONFIGURATION and GETSTATUS
const [jsonData, setData] = useState<string>("") // to pass the normalized JSON
const [commandDone, setCommandDone] = React.useState<boolean>(false) // if the execution of this fetching was completed or not
const [errorResponse, setError] = useState<string>("") // eventual error
const controller = useRef<AbortController | null>(null); // still to manage
setCurrentIP(ip)
const urlCommand = `....` // command construction with arguments passed
useEffect(() => {
fetchData()
}, [])
const fetchData = async () => {
await fetch(urlCommand, {
method: "GET",
headers: { "Content-Type": "application/json" }
}).then(res =>{
res.json().then(data => {
switch (commandType) {
case CommandTypes.LOGIN:{
setData(data)
}
break;
case CommandTypes.GETCONFIGURATION: {
// manage returned JSON and normalize it to return another JSON and fill the single element data,
// like forEach element of the single element fill it with the relative value key in normalized json
}
break;
case CommandTypes.GETSTATUS : {
// same as GETCONFIGURATION
}
break;
default : { }
break;
}
setCommandDone(true)
})
}).catch(error => {
setError(error)
setCommandDone(false)
})
}
return {currentIp, commandDone, jsonData, errorResponse}
}
hmm, if useGetData doesn't return a Promise, then you never need to call Promise.all at usage sites. every time you call that version of useGetData it's firing-and-forgetting those requests. the next line of code after the call will happen immediately while the fetch is still happening in the background
this also means you have no way to sequence things from the call site (for example no way to ensure that LOGIN completes before the other requests begin)
i'm guessing that's not actually desired and it's a mistake for useGetData to not be returning a Promise?
i feel like there's some fundamental misunderstanding here. did you read the MDN page that i linked to earlier? is there anything that didn't make sense on that page?
there's also https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Async_JS if you want a longer conceptual overview
i sketched up an example of what i think is the flow you want. if i understand everything correctly this will give you as much concurrency as is possible for your use case:
Preview:```ts
...
const operationsForAllIps = allIps.map(async ip => {
const loginResponse = await fetch(makeLoginUrl(ip), {
// ...
})
const configurationOperation = fetch(
makeConfigurationUrl(ip),
{
// ... (includes session id from loginResponse)
}
)
const statusOperation = fetch(makeStatusUrl(ip), {
// ... (includes session id from loginResponse)
})
// do configuration and status operations concurrently:
return Promise.all([
configurationOperation,
statusOperation,
])
})
...```
that obviously elides a bunch of details you've had in your examples, but i just want to focus on the overall flow. once you understand that you should be able to add things back in