Ktor - Create Multiple Subdomains Programatically - kotlin

Okay so this may sound like a stupid question, but I really need to know, is there a way to create multiple domains programatically with Ktor. For example, let's say that I have a domain: example.com
Now I need the logic on my backend server to create a new subdomain for each user that register on my website. For example, when John register, I want to immediately be able to create a new subdomain: john.example.com . Now I'm not sure what and how this can be achieved, that's why I'm asking here for some directions?
And if that's too complex, then is there a way to create multiple endpoints dynamically from the code, after each and every user registration on my website, like: example.com/John ?
Is there any good resource that I can read about that?

On the Ktor side, you can add routes dynamically after the server startup and use the host route builder to match the requested host. Additionally, you need to add DNS entries programmatically as #Stephen Jennings said. Here's an example where after 5 seconds the route for the host john.example.com is added. You can test it locally with the entry 127.0.0.1 john.example.com in the /etc/hosts file.
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import kotlinx.coroutines.*
fun main() {
val server = embeddedServer(Netty, port = 4444) {
routing {
get("/example") {
call.respondText { "example" }
}
}
}
server.start(wait = false)
CoroutineScope(Dispatchers.IO).launch {
delay(5000)
val routing = server.application.feature(Routing)
routing.addRoutesForHost("john.example.com")
}
}
fun Route.addRoutesForHost(host: String) {
host(host) {
get("/hello") {
call.respondText { "Hello ${call.request.headers[HttpHeaders.Host]}" }
}
}
}

Related

NestJS - Correct way of setting redis subscribers in a custom provider

I'm building a simple application that will subscribe to a number of channels in a redis database.
Given the following code in the redis service:
// redis.service.ts
import { Injectable } from '#nestjs/common';
const NRP = require('node-redis-pubsub');
const config = {
port: 6379,
};
#Injectable()
export class RedisService {
private nrpClient = new NRP(config)
constructor() {
this.simpleListener()
}
simpleListener() {
this.nrpClient.on('__keyspace#0__:mykey', (data) => {
console.log(data)
})
}
}
and the code in the redis module:
// redis.module.ts
import { Module } from '#nestjs/common';
import { RedisService } from './redis.service';
#Module({
providers: [RedisService]
})
export class RedisModule {}
I've achieved the expected behavior for my application.
If I enter a session in my redis-cli and run:
127.0.0.1:6379> SADD mykey "test"
Then the NestJS logger prints the following:
[Nest] 306987 - 05/04/2021, 9:01:41 PM [NestApplication] Nest application successfully started +5ms
sadd
My question here is concerning my implementation design, rather than it's functionality.
There's a great lack of examples and documentation regarding the subject so I followed my instincts and wrote the code above based on this recommendation.
Then, given that a provided class will be a singleton if registered as a "provider" in the redis module, I simply did that and called the function that creates the subscription in the redis service constructor.
I'm just worried that I'm not following the best guidelines in building a custom NestJS provider, also I don't really know if setting up the listeners in the constructor is the best idea.
Is this the best/correct way of implementing the desired behavior?

KTor site not reachable

I want to make a simple http server using ktor. However, when I enter the site (127.0.0.1:8080 or 0.0.0.0:8080), it just isn't there. It doesn't print and doesn't respond.
However if I use NanoHttpd instead of ktor, everything works fine. What is my issue?
import io.ktor.application.call
import io.ktor.http.ContentType
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.routing
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
fun main() {
val server = embeddedServer(Netty, port = 8080) {
routing {
get("/") {
println("TEST")
call.respondText("Hello World!", ContentType.Text.Plain)
}
}
}
server.start(wait = true)
}
The output is just:
[main] INFO ktor.application - No ktor.deployment.watch patterns specified, automatic reload is not active
[main] INFO ktor.application - Responding at http://0.0.0.0:8080
It could be one of the following things:
The application code
The run configuration
I am leaning towards there being a problem with the run configuration rather than the application code.
Application code
Even though I think your issue is with the run configuration, in case that it isn't, I'm providing sample code here.
When I use the IntelliJ Ktor plugin, the Ktor app is bootstrapped as follows:
Application.kt
package com.example
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.routing.*
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
#kotlin.jvm.JvmOverloads
#Suppress("unused") // Referenced in application.conf
fun Application.module(testing: Boolean = false) {
routing {
get("/") {
call.respondText("Hello, world!", ContentType.Text.Plain)
}
}
}
application.conf
ktor {
deployment {
port = 8080
port = ${?PORT}
}
application {
modules = [ com.example.ApplicationKt.module ]
}
}
I've provided an example Ktor code base here: https://gitlab.com/tinacious/ktor-example
Run configuration
It could be your run configuration in IntelliJ. It needs to be set up as a Kotlin script (and not an Application). When it's set up as an Application, I get the same error you do. Here is how to set up the run configuration I have, allowing me to run the server in IntelliJ:
Add a configuration
Choose Kotlin script from the Templates section. Do not choose Application.
Near the bottom where it says "Use classpath of module" choose your application.main.
Near the top where it says "Main class" you should be able to choose your main application. I found this only showed up after I chose the classpath of the module.
Here are the relevant sections in the configuration:
Here is what I describe in step 4, i.e. I can choose my main class after the class path is added:
The run symbol should be a Kotlin logo:
I would recommend installing the IntelliJ Ktor plugin for bootstrapping your project. It uses Gradle and bootstraps everything so when you run ./gradlew run, you are running it properly and can access it without the manual build configuration step.

Ktor application not running on my computer

I am trying to learn to use ktor and I'm trying to display the text "Hello Ktor" at the root path but all I keep getting is this site can't be reached.
This is my code:
import io.ktor.application.*
import io.ktor.http.ContentType
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.routing
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
private val userData = "{\"users\": [\"Timi\", \"Tomi\", \"Temi\"]}"
#Suppress("unused") // Referenced in application.conf
#kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
routing {
get("/") {
call.respondText("Hello Ktor", ContentType.Text.Plain)
}
}
}
What am I doing wrong?
Your code is fine.
I think you just need to access it correctly from browser.
Try
127.0.0.1:8080
or
localhost:8080
or simply follow nice tutorial from official website.
Are you trying to run without a main?
Did you follow this guide? https://ktor.io/quickstart/quickstart/gradle.html#intellij-extract-out-configuration-data
If you want to start from main, use embeddedServer. Otherwise you have to set the mainClassName.

Hot to add POST interceptor to aurelia http client

Basically, the question says it all :). The scenario is as follows: I have some python models that are being passed between the browser, and the server. Python convention for naming things is to use underscores, and js convention is to camelCase everything. So I figured, I'd just create an http request interceptor to convert between python_models and jsModels. Is there a simple way to accomplish that?
I'm also looking for a way to do the inverse, so camelCase to that-case :)
If you're using aurelia-http-client, you can use a reviver.
import {HttpClient} from 'aurelia-http-client';
import {Person} from './models';
export class PersonService {
constructor(){
this.http = new HttpClient().configure(x=> {
x.withReviver((k,v) => {
return typeof v === 'object' ? new Person(v) : v;
});
});
}
getPeople(){
return this.http.get('/people');
}
}
This only works for aurelia-http-client and not aurelia-fetch-client. It has been talked about in the fetch spec, but I don't believe it is currently implemented.
Check the following for more information:
(my) Best Practices in Aurelia: The Model
https://github.com/whatwg/fetch/issues/104

Dynamic adapter pathForType based on auth id

Is there any way to include a user's authentication uid in a model adapter's path? For example, suppose you have a chat application, and a conversation model to represent a private message session between two users, where the data is stored something like this:
{
"conversations": {
"<userAuthUID>": {
"convo1": {...},
"convo2": {...},
...
},
"<anotherUserAuthUID>": {
...
}
}
}
So, with this structure, the adapter's path would need to be conversations/<currentUserAuthUID>.
(FYI this is an ember-cli project, if that makes any difference.)
It seems to be working using the following:
// adapters/conversation.js
import Ember from 'ember';
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
pathForType: function(type) {
//get the firebase authentication data via the `Firebase` instance
//that i have injected into my app via an initializer
var authData = this.container.lookup('app:firebase').getAuth();
return Ember.String.pluralize(type) + '/' + authData.uid;
}
});