diff options
| author | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-07-11 15:50:00 +0200 |
|---|---|---|
| committer | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-07-11 15:50:00 +0200 |
| commit | 3b4282861d8ac521dcb5cf79330fcc4eac59ba44 (patch) | |
| tree | 4c296d41b70e4bbf77a619f00842495ce39f6aec | |
| parent | 994f18e532c0501a51fd9bb8563d6ee351785e04 (diff) | |
Types + Exports: Return JSON and use error level
| -rw-r--r-- | exports/exports.go | 36 | ||||
| -rw-r--r-- | internal/types/error.go | 54 | ||||
| -rw-r--r-- | state.go | 12 | ||||
| -rw-r--r-- | wrappers/python/src/__init__.py | 57 | ||||
| -rw-r--r-- | wrappers/python/src/main.py | 6 |
5 files changed, 131 insertions, 34 deletions
diff --git a/exports/exports.go b/exports/exports.go index 9f5d18c..468c5a4 100644 --- a/exports/exports.go +++ b/exports/exports.go @@ -15,6 +15,7 @@ import "C" import ( "errors" + "encoding/json" "fmt" "unsafe" @@ -92,7 +93,7 @@ func ErrorToString(error error) string { return "" } - return eduvpn.GetErrorTraceback(error) + return eduvpn.GetErrorJSONString(error) } //export CancelOAuth @@ -107,40 +108,55 @@ func CancelOAuth(name *C.char) *C.char { return C.CString(cancelErrString) } +type configJSON struct { + config string `json:"config"` + configType string `json:"config_type"` +} + +func getConfigJSON(config string, configType string) *C.char { + json, jsonErr := json.Marshal(&configJSON{config, configType}) + + if jsonErr != nil { + panic(jsonErr) + } + + return C.CString(string(json)) +} + //export GetConfigSecureInternet -func GetConfigSecureInternet(name *C.char, orgID *C.char, forceTCP C.int) (*C.char, *C.char, *C.char) { +func GetConfigSecureInternet(name *C.char, orgID *C.char, forceTCP C.int) (*C.char, *C.char) { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { - return nil, nil, C.CString(ErrorToString(stateErr)) + return nil, C.CString(ErrorToString(stateErr)) } forceTCPBool := forceTCP == 1 config, configType, configErr := state.GetConfigSecureInternet(C.GoString(orgID), forceTCPBool) - return C.CString(config), C.CString(configType), C.CString(ErrorToString(configErr)) + return getConfigJSON(config, configType), C.CString(ErrorToString(configErr)) } //export GetConfigInstituteAccess -func GetConfigInstituteAccess(name *C.char, url *C.char, forceTCP C.int) (*C.char, *C.char, *C.char) { +func GetConfigInstituteAccess(name *C.char, url *C.char, forceTCP C.int) (*C.char, *C.char) { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { - return nil, nil, C.CString(ErrorToString(stateErr)) + return nil, C.CString(ErrorToString(stateErr)) } forceTCPBool := forceTCP == 1 config, configType, configErr := state.GetConfigInstituteAccess(C.GoString(url), forceTCPBool) - return C.CString(config), C.CString(configType), C.CString(ErrorToString(configErr)) + return getConfigJSON(config, configType), C.CString(ErrorToString(configErr)) } //export GetConfigCustomServer -func GetConfigCustomServer(name *C.char, url *C.char, forceTCP C.int) (*C.char, *C.char, *C.char) { +func GetConfigCustomServer(name *C.char, url *C.char, forceTCP C.int) (*C.char, *C.char) { nameStr := C.GoString(name) state, stateErr := GetVPNState(nameStr) if stateErr != nil { - return nil, nil, C.CString(ErrorToString(stateErr)) + return nil, C.CString(ErrorToString(stateErr)) } forceTCPBool := forceTCP == 1 config, configType, configErr := state.GetConfigCustomServer(C.GoString(url), forceTCPBool) - return C.CString(config), C.CString(configType), C.CString(ErrorToString(configErr)) + return getConfigJSON(config, configType), C.CString(ErrorToString(configErr)) } //export GetDiscoOrganizations diff --git a/internal/types/error.go b/internal/types/error.go index fda7c9c..e5bd082 100644 --- a/internal/types/error.go +++ b/internal/types/error.go @@ -2,10 +2,22 @@ package types import ( "errors" + "encoding/json" "fmt" ) +type ErrorLevel int8 + +const ( + // All other errors + ERR_OTHER ErrorLevel = iota + + // The error is just here as additional info + ERR_INFO +) + type WrappedErrorMessage struct { + Level ErrorLevel Message string Err error } @@ -60,3 +72,45 @@ func GetErrorCause(err error) error { } return err } + +func GetErrorLevel(err error) ErrorLevel { + var wrappedErr *WrappedErrorMessage + + if errors.As(err, &wrappedErr) { + return wrappedErr.Level + } + return ERR_OTHER +} + +type WrappedErrorMessageJSON struct { + Level ErrorLevel `json:"level"` + Cause string `json:"cause"` + Traceback string `json:"traceback"` +} + + +func GetErrorJSONString(err error) string { + var wrappedErr *WrappedErrorMessage + + var level ErrorLevel + var cause error + var traceback string + + if errors.As(err, &wrappedErr) { + level = wrappedErr.Level + cause = wrappedErr.Cause() + traceback = wrappedErr.Traceback() + } else { + level = ERR_OTHER + cause = err + traceback = err.Error() + } + + + json, jsonErr := json.Marshal(&WrappedErrorMessageJSON{Level: level, Cause: cause.Error(), Traceback: traceback}) + + if jsonErr != nil { + panic(jsonErr) + } + return string(json) +} @@ -336,10 +336,18 @@ func (state *VPNState) SetDisconnected() error { return nil } +func GetErrorCause(err error) error { + return types.GetErrorCause(err) +} + +func GetErrorLevel(err error) types.ErrorLevel { + return types.GetErrorLevel(err) +} + func GetErrorTraceback(err error) string { return types.GetErrorTraceback(err) } -func GetErrorCause(err error) error { - return types.GetErrorCause(err) +func GetErrorJSONString(err error) string { + return types.GetErrorJSONString(err) } diff --git a/wrappers/python/src/__init__.py b/wrappers/python/src/__init__.py index f361ad1..0451f61 100644 --- a/wrappers/python/src/__init__.py +++ b/wrappers/python/src/__init__.py @@ -1,8 +1,10 @@ from ctypes import * from collections import defaultdict +from enum import Enum import pathlib import platform -from typing import Tuple +from typing import Tuple, Optional +import json _lib_prefixes = defaultdict( lambda: "lib", @@ -33,15 +35,14 @@ try: except: lib = cdll.LoadLibrary(str(pathlib.Path(__file__).parent / "lib" / _libfile)) +class ErrorLevel(Enum): + ERR_OTHER = 0 + ERR_INFO = 1 class DataError(Structure): _fields_ = [("data", c_void_p), ("error", c_void_p)] -class MultipleDataError(Structure): - _fields_ = [("data", c_void_p), ("other_data", c_void_p), ("error", c_void_p)] - - VPNStateChange = CFUNCTYPE(None, c_char_p, c_char_p, c_char_p, c_char_p) # Exposed functions @@ -51,17 +52,17 @@ lib.GetConfigSecureInternet.argtypes, lib.GetConfigSecureInternet.restype = [ c_char_p, c_char_p, c_int, -], MultipleDataError +], DataError lib.GetConfigInstituteAccess.argtypes, lib.GetConfigInstituteAccess.restype = [ c_char_p, c_char_p, c_int, -], MultipleDataError +], DataError lib.GetConfigCustomServer.argtypes, lib.GetConfigCustomServer.restype = [ c_char_p, c_char_p, c_int, -], MultipleDataError +], DataError lib.Deregister.argtypes, lib.Deregister.restype = [c_char_p], c_void_p lib.Register.argtypes, lib.Register.restype = [ c_char_p, @@ -87,6 +88,13 @@ lib.SetSearchServer.argtypes, lib.SetSearchServer.restype = [c_char_p], c_void_p lib.FreeString.argtypes, lib.FreeString.restype = [c_void_p], None +class WrappedError: + def __init__(self, traceback: str, cause: str, level: ErrorLevel): + self.traceback = traceback + self.cause = cause + self.level = level + + def encode_args(args, types): for arg, t in zip(args, types): # c_char_p needs the str to be encoded to bytes @@ -107,24 +115,33 @@ def get_ptr_string(ptr: c_void_p) -> str: return string.decode() return "" +def get_ptr_error(ptr: c_void_p) -> Optional[WrappedError]: + error_string = get_ptr_string(ptr) + + if not error_string: + return None + + error_json = json.loads(error_string) + + if not error_json: + return None + + level = error_json["level"] + traceback = error_json["traceback"] + cause = error_json["cause"] + return WrappedError(traceback, cause, ErrorLevel(level)) def get_data_error(data_error: DataError) -> Tuple[str, str]: data = get_ptr_string(data_error.data) - error = get_ptr_string(data_error.error) + error = get_ptr_error(data_error.error) + if not error: + error = "" + else: + error = error.traceback return data, error -def get_multiple_data_error( - multiple_data_error: MultipleDataError, -) -> Tuple[str, str, str]: - data = get_ptr_string(multiple_data_error.data) - other_data = get_ptr_string(multiple_data_error.other_data) - error = get_ptr_string(multiple_data_error.error) - return data, other_data, error - - decode_map = { - c_void_p: get_ptr_string, + c_void_p: get_ptr_error, DataError: get_data_error, - MultipleDataError: get_multiple_data_error, } diff --git a/wrappers/python/src/main.py b/wrappers/python/src/main.py index 3707d16..6f4b140 100644 --- a/wrappers/python/src/main.py +++ b/wrappers/python/src/main.py @@ -1,5 +1,4 @@ from . import lib, VPNStateChange, encode_args, decode_res -from enum import Enum from typing import Optional, Tuple import threading from .event import StateType, EventHandler @@ -103,7 +102,7 @@ class EduVPN(object): # The event is set in self.set_profile self.profile_event = threading.Event() - config, config_type, config_err = self.go_function(func, url, force_tcp) + config_json, config_err = self.go_function(func, url, force_tcp) self.profile_event = None self.location_event = None @@ -111,6 +110,9 @@ class EduVPN(object): if config_err: raise Exception(config_err) + config = config_json["config"] + config_type = config_json["config_type"] + return config, config_type def get_config_custom_server( |
