xref: /unit/go/unit.go (revision 1713:f5ba5973a0a3)
1/*
2 * Copyright (C) Max Romanov
3 * Copyright (C) NGINX, Inc.
4 */
5
6package unit
7
8/*
9#include "nxt_cgo_lib.h"
10*/
11import "C"
12
13import (
14	"fmt"
15	"net/http"
16	"sync"
17	"unsafe"
18)
19
20type cbuf struct {
21	b C.uintptr_t
22	s C.size_t
23}
24
25func buf_ref(buf []byte) C.uintptr_t {
26	if len(buf) == 0 {
27		return 0
28	}
29
30	return C.uintptr_t(uintptr(unsafe.Pointer(&buf[0])))
31}
32
33type string_header struct {
34	Data unsafe.Pointer
35	Len int
36}
37
38func str_ref(s string) *C.char {
39	header := (*string_header)(unsafe.Pointer(&s))
40
41	return (*C.char)(header.Data)
42}
43
44func (buf *cbuf) init_bytes(b []byte) {
45	buf.b = buf_ref(b)
46	buf.s = C.size_t(len(b))
47}
48
49type slice_header struct {
50	Data unsafe.Pointer
51	Len int
52	Cap int
53}
54
55func (buf *cbuf) GoBytes() []byte {
56	if buf == nil {
57		var b [0]byte
58		return b[:0]
59	}
60
61	header := &slice_header{
62		Data: unsafe.Pointer(uintptr(buf.b)),
63		Len: int(buf.s),
64		Cap: int(buf.s),
65	}
66
67	return *(*[]byte)(unsafe.Pointer(header))
68}
69
70func GoBytes(buf unsafe.Pointer, size C.int) []byte {
71	bytesHeader := &slice_header{
72		Data: buf,
73		Len: int(size),
74		Cap: int(size),
75	}
76
77	return *(*[]byte)(unsafe.Pointer(bytesHeader))
78}
79
80func GoStringN(sptr *C.nxt_unit_sptr_t, l C.int) string {
81	p := unsafe.Pointer(sptr)
82	b := uintptr(p) + uintptr(*(*C.uint32_t)(p))
83
84	return C.GoStringN((*C.char)(unsafe.Pointer(b)), l)
85}
86
87func nxt_go_warn(format string, args ...interface{}) {
88	str := fmt.Sprintf("[go] " + format, args...)
89
90	C.nxt_cgo_warn(str_ref(str), C.uint32_t(len(str)))
91}
92
93func nxt_go_alert(format string, args ...interface{}) {
94	str := fmt.Sprintf("[go] " + format, args...)
95
96	C.nxt_cgo_alert(str_ref(str), C.uint32_t(len(str)))
97}
98
99type handler_registry struct {
100	sync.RWMutex
101	next uintptr
102	m map[uintptr]*http.Handler
103}
104
105var handler_registry_ handler_registry
106
107func set_handler(handler *http.Handler) uintptr {
108
109	handler_registry_.Lock()
110	if handler_registry_.m == nil {
111		handler_registry_.m = make(map[uintptr]*http.Handler)
112		handler_registry_.next = 1
113	}
114
115	h := handler_registry_.next
116	handler_registry_.next += 1
117	handler_registry_.m[h] = handler
118
119	handler_registry_.Unlock()
120
121	return h
122}
123
124func get_handler(h uintptr) http.Handler {
125	handler_registry_.RLock()
126	defer handler_registry_.RUnlock()
127
128	return *handler_registry_.m[h]
129}
130
131func reset_handler(h uintptr) {
132
133	handler_registry_.Lock()
134	if handler_registry_.m != nil {
135		delete(handler_registry_.m, h)
136	}
137
138	handler_registry_.Unlock()
139}
140
141func ListenAndServe(addr string, handler http.Handler) error {
142	if handler == nil {
143		handler = http.DefaultServeMux
144	}
145
146	h := set_handler(&handler)
147
148	rc := C.nxt_cgo_run(C.uintptr_t(h))
149
150	reset_handler(h)
151
152	if rc != 0 {
153		return http.ListenAndServe(addr, handler)
154	}
155
156	return nil
157}
158