<commit_before>package haxeremote

import (
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/url"
	"strconv"
	"sync"
)

var haxeRemoteFuncs = map[string]func(interface{}) interface{}{}
var haxeRemoteFuncsMutex sync.Mutex

func AddFunc(name string, fn func(interface{}) interface{}) {
	haxeRemoteFuncsMutex.Lock()
	haxeRemoteFuncs[name] = fn
	haxeRemoteFuncsMutex.Unlock()
}

func callHaxeRemoteFunc(name string, arg interface{}) (interface{}, error) {
	haxeRemoteFuncsMutex.Lock()
	fn, ok := haxeRemoteFuncs[name]
	haxeRemoteFuncsMutex.Unlock()
	if !ok {
		return nil, errors.New("could not find remote func " + name + " in CallHaxeRemoteFunc()")
	}
	return fn(arg), nil
}

func HttpHandler(rw http.ResponseWriter, req *http.Request) {
	// TODO add further validaton of the request as from a valid Haxe user here?

	if req.Header.Get("X-Haxe-Remoting") != "1" {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic("header does not contain X-Haxe-Remoting=1")
		return
	}

	p, e := ioutil.ReadAll(req.Body)
	//fmt.Printf("DEBUG Request: %#v\nBody: %s, err=%v\n", *req, p, e)
	if e != nil {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic(e)
		return
	}
	if len(p) < 4 {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic("no body")
		return
	}
	if string(p[:4]) != "__x=" {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic("__x= not found")
		return
	}
	une, err := url.QueryUnescape(string(p[4:]))
	if err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic(err)
		return
	}
	buf := []byte(une)
	//fmt.Printf("DEBUG URL unescaped = %s\n", string(buf))
	var targetA interface{}
	target := ""
	targetA, buf, err = Unserialize(buf)
	for i, t := range targetA.([]interface{}) {
		if i > 0 {
			target += "."
		}
		target += t.(string)
	}
	//fmt.Printf("DEBUG Unserialized Target decoded=%s, remaining=%s, error=%v\n", target, buf, err)
	var args interface{}
	args, buf, err = Unserialize(buf)
	//fmt.Printf("DEBUG Unserialized Args decoded=%v, remaining=%s, error=%v\n", args, buf, err)

	results, err := callHaxeRemoteFunc(target, args)
	if err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic(err)
		return
	}
	reply := "hxr" + Serialize(results)
	fmt.Fprintln(rw, reply)
	//fmt.Println("DEBUG reply: " + reply)
}

/* Haxe serialization prefixes :
a : array
b : hash
c : class
d : Float
e : reserved (float exp)
f : false
g : object end
h : array/list/hash end
i : Int
j : enum (by index)
k : NaN
l : list
m : -Inf
n : null
o : object
p : +Inf
q : haxe.ds.IntMap
r : reference
s : bytes (base64)
t : true
u : array nulls
v : date
w : enum
x : exception
y : urlencoded string<commit_msg>add debug msg comment<commit_after>package haxeremote

import (
	"encoding/base64"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/url"
	"strconv"
	"sync"
)

var haxeRemoteFuncs = map[string]func(interface{}) interface{}{}
var haxeRemoteFuncsMutex sync.Mutex

func AddFunc(name string, fn func(interface{}) interface{}) {
	haxeRemoteFuncsMutex.Lock()
	haxeRemoteFuncs[name] = fn
	haxeRemoteFuncsMutex.Unlock()
}

func callHaxeRemoteFunc(name string, arg interface{}) (interface{}, error) {
	haxeRemoteFuncsMutex.Lock()
	fn, ok := haxeRemoteFuncs[name]
	haxeRemoteFuncsMutex.Unlock()
	if !ok {
		return nil, errors.New("could not find remote func " + name + " in CallHaxeRemoteFunc()")
	}
	return fn(arg), nil
}

func HttpHandler(rw http.ResponseWriter, req *http.Request) {
	// TODO add further validaton of the request as from a valid Haxe user here?

	if req.Header.Get("X-Haxe-Remoting") != "1" {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic("header does not contain X-Haxe-Remoting=1")
		return
	}

	p, e := ioutil.ReadAll(req.Body)
	//fmt.Printf("DEBUG Request: %#v\nBody: %s, err=%v\n", *req, p, e)
	if e != nil {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic(e)
		return
	}
	if len(p) < 4 {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic("no body")
		return
	}
	if string(p[:4]) != "__x=" {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic("__x= not found")
		return
	}
	une, err := url.QueryUnescape(string(p[4:]))
	if err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic(err)
		return
	}
	buf := []byte(une)
	//fmt.Printf("DEBUG URL unescaped = %s\n", string(buf))
	var targetA interface{}
	target := ""
	targetA, buf, err = Unserialize(buf)
	for i, t := range targetA.([]interface{}) {
		if i > 0 {
			target += "."
		}
		target += t.(string)
	}
	//fmt.Printf("DEBUG Unserialized Target decoded=%s, remaining=%s, error=%v\n", target, buf, err)
	var args interface{}
	args, buf, err = Unserialize(buf)
	//fmt.Printf("DEBUG Unserialized Args decoded=%v, remaining=%s, error=%v\n", args, buf, err)

	results, err := callHaxeRemoteFunc(target, args)
	if err != nil {
		rw.WriteHeader(http.StatusBadRequest)
		log.Panic(err)
		return
	}
	reply := "hxr" + Serialize(results)
	fmt.Fprintln(rw, reply)
	//fmt.Printf("DEBUG haxe http remote results: %v serialized-reply: %s\n", results, reply)
}

/* Haxe serialization prefixes :
a : array
b : hash
c : class
d : Float
e : reserved (float exp)
f : false
g : object end
h : array/list/hash end
i : Int
j : enum (by index)
k : NaN
l : list
m : -Inf
n : null
o : object
p : +Inf
q : haxe.ds.IntMap
r : reference
s : bytes (base64)
t : true
u : array nulls
v : date
w : enum
x : exception
y : urlencoded string
{'fraction_non_alphanumeric': 0.15548495608297513, 'fraction_numerical': 0.0037376191366099796, 'mean_word_length': 4.102001906577693, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3338584', 'n_tokens_mistral': 2141, 'n_tokens_neox': 2080, 'n_words': 525}