URL shortener: Difference between revisions

Added Wren
(Added Wren)
Line 976:
react whenever signal(SIGINT) { $shorten.stop; exit; }
</lang>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-json}}
An embedded program with a Go host so we can use its net/http module.
<lang ecmascript>/* url_shortener.wren */
 
import "./json" for JSON
import "random" for Random
 
var Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
var MethodPost = "POST"
var MethodGet = "GET"
var StatusBadRequest = 400
var StatusFound = 302
var StatusNotFound = 404
 
var Db = {}
var Rand = Random.new()
 
var GenerateKey = Fn.new { |size|
var key = List.filled(size, null)
var le = Chars.count
for (i in 0...size) key[i] = Chars[Rand.int(le)]
return key.join()
}
 
class ResponseWriter {
foreign static writeHeader(statusCode)
foreign static fprint(str)
}
 
class Request {
foreign static method
foreign static body
foreign static urlPath
}
 
class Http {
foreign static host
 
static serve() {
if (Request.method == MethodPost) {
var body = Request.body
var sh = JSON.parse(body)["long"]
var short = GenerateKey.call(8)
Db[short] = sh
ResponseWriter.fprint("The shortened URL: http://%(host)/%(short)\n")
} else if (Request.method == MethodGet) {
var path = Request.urlPath[1..-1]
if (Db.containsKey(path)) {
redirect(Db[path], StatusFound)
} else {
ResponseWriter.writeHeader(StatusNotFound)
ResponseWriter.fprint("No such shortened url: http://%(host)/%(path)\n")
}
} else {
ResponseWriter.writeHeader(StatusNotFound)
ResponseWriter.fprint("Unsupported method: %(Request.method)\n")
}
}
 
foreign static redirect(url, code)
}</lang>
We now embed this script in the following Go program and build it.
<lang go>/* go build url_shortener.go */
 
package main
 
import (
"fmt"
wren "github.com/crazyinfin8/WrenGo"
"io/ioutil"
"log"
"net/http"
"strings"
)
 
type any = interface{}
 
var fileName = "url_shortener.wren"
var host = "localhost:8000"
 
var vm *wren.VM
 
var gw http.ResponseWriter
var greq *http.Request
 
func serveHTTP(w http.ResponseWriter, req *http.Request) {
gw, greq = w, req
wrenVar, _ := vm.GetVariable(fileName, "Http")
wrenClass, _ := wrenVar.(*wren.Handle)
defer wrenClass.Free()
wrenMethod, _ := wrenClass.Func("serve()")
defer wrenMethod.Free()
wrenMethod.Call()
}
 
func writeHeader(vm *wren.VM, parameters []any) (any, error) {
statusCode := int(parameters[1].(float64))
gw.WriteHeader(statusCode)
return nil, nil
}
 
func fprint(vm *wren.VM, parameters []any) (any, error) {
str := parameters[1].(string)
fmt.Fprintf(gw, str)
return nil, nil
}
 
func method(vm *wren.VM, parameters []any) (any, error) {
res := greq.Method
return res, nil
}
 
func body(vm *wren.VM, parameters []any) (any, error) {
res, _ := ioutil.ReadAll(greq.Body)
return res, nil
}
 
func urlPath(vm *wren.VM, parameters []any) (any, error) {
res := greq.URL.Path
return res, nil
}
 
func getHost(vm *wren.VM, parameters []any) (any, error) {
return host, nil
}
 
func redirect(vm *wren.VM, parameters []any) (any, error) {
url := parameters[1].(string)
code := int(parameters[2].(float64))
http.Redirect(gw, greq, url, code)
return nil, nil
}
 
func moduleFn(vm *wren.VM, name string) (string, bool) {
if name != "meta" && name != "random" && !strings.HasSuffix(name, ".wren") {
name += ".wren"
}
return wren.DefaultModuleLoader(vm, name)
}
 
func main() {
cfg := wren.NewConfig()
cfg.LoadModuleFn = moduleFn
vm = cfg.NewVM()
 
responseWriterMethodMap := wren.MethodMap{
"static writeHeader(_)": writeHeader,
"static fprint(_)": fprint,
}
 
requestMethodMap := wren.MethodMap{
"static method": method,
"static body": body,
"static urlPath": urlPath,
}
 
httpMethodMap := wren.MethodMap{
"static host": getHost,
"static redirect(_,_)": redirect,
}
 
classMap := wren.ClassMap{
"ResponseWriter": wren.NewClass(nil, nil, responseWriterMethodMap),
"Request": wren.NewClass(nil, nil, requestMethodMap),
"Http": wren.NewClass(nil, nil, httpMethodMap),
}
 
module := wren.NewModule(classMap)
vm.SetModule(fileName, module)
vm.InterpretFile(fileName)
http.HandleFunc("/", serveHTTP)
log.Fatal(http.ListenAndServe(host, nil))
vm.Free()
}</lang>
{{out}}
Sample output (abbreviated) including building and starting the server from Ubuntu 20.04 terminal and entering a valid and then an invalid shortened URL:
<pre>
$ go build url_shortener.go
 
$ ./url_shortener &
 
$ curl -X POST 'localhost:8000'/ \
> -H 'Content-Type: application/json' \
> -d '{
> "long": "https://www.cockroachlabs.com/docs/stable/build-a-go-app-with-cockroachdb.html"
> }'
The shortened URL: http://localhost:8000/RRyYg8tK
 
$ curl -L http://localhost:8000/RRyYg8tK
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Learn how to use CockroachDB from a simple Go application with the Go pgx driver.">
 
....
 
</html>
 
$ curl -L http://localhost:8000/3DOPwhRv
No such shortened url: http://localhost:8000/3DOPwhRv
</pre>
9,483

edits