Simplifying device creation in sip.conf - asterisk

I often have to define many similar devices in sip.conf like this:
[device](!)
; setting some parameters
[device01](device)
callerid=dev01 <01>
[device02](device)
callerid=dev02 <02>
; ...
[deviceXX](device)
callerid=devXX <XX>
The question is perhaps I could avoid setting device-name specific parameters by using some variable like following?
[device](!)
callerid=dev${DEVICE_NAME:-2} <${DEVICE_NAME:-2}>
; setting some parameters
[device01](device)
[device02](device)
; ...
[deviceXX](device)
P.S.
It would be perfect, if there was some device constructor, so I could reduce the script to following, but, I think, that is not possible in Asterisk.
[device](!)
callerid=dev${DEVICE_NAME:-2} <${DEVICE_NAME:-2}>
; setting some parameters
;[device${MAGIC_LOOP(1,XX,leading_zeroes)}](device)

I've had good results writing a small program that takes care of it. It checks for a line saying something like
------- Automatically generated -------
and whatever is after that line, it's going to be regenerated as soon as it detects that there are new values for it (it could be from a database or from a text file). Then, I run it with supervisor and it checks every XX seconds if there are changes.
If there are changes, it issues a sip reload command after updating the sip.conf file
I wrote it in python, but whatever language you feel comfortable with should work just fine.
That's how I managed that and has been working fine so far (after a couple of months). I'd be extremely interested in learning about other approaches though. It's basically this (called from another script with supervisor):
users = get_users_logic()
#get the data that will me used on the sip.conf file
data_to_be_hashed = reduce(lambda x, y: x + y, map(lambda x: x['username'] + x['password'] + x['company_prefix'], users))
m = hashlib.md5()
m.update(str(data_to_be_hashed).encode("ascii"))
new_md5 = m.hexdigest()
last_md5 = None
try:
file = open(os.path.dirname(os.path.realpath(__file__)) + '/lastMd5.txt', 'r')
last_md5 = file.read().rstrip()
file.close()
except:
pass
# if it changed...
if new_md5 != last_md5:
#needs update
with open(settings['asterisk']['path_to_sip_conf'], 'r') as file:
sip_content = file.read().rstrip()
parts = sip_content.split(";-------------- BEYOND THIS POINT IT IS AUTO GENERATED --------------;")
sip_content = parts[0].rstrip()
sip_content += "\n\n;-------------- BEYOND THIS POINT IT IS AUTO GENERATED --------------;\n\n"
for user in users:
m = hashlib.md5()
m.update(("%s:sip.ellauri.it:%s" % (user['username'], user['password'])).encode("ascii"))
md5secret = m.hexdigest()
sip_content += "[%s]\ntype = friend\ncontext = %sLocal\nmd5secret = %s\nhost = dynamic\n\n" % (
user['username'], user['company_prefix'], md5secret)
#write the sip.conf file
f = open(settings['asterisk']['path_to_sip_conf'], 'w')
print(sip_content, file=f)
f.close()
subprocess.call('asterisk -x "sip reload"', shell=True)
#write the new md5
f = open(os.path.dirname(os.path.realpath(__file__)) + '/lastMd5.txt', 'w')
print(new_md5, file=f)
f.close()

Related

python 2.7.5: run a whole function in background

I am a beginner with python. I want to run a whole function in the background (because it can take a while or even fail).
Here is the function:
def backup(str):
command = barman_bin + " backup " + str
log_maif.info("Lancement d'un backup full:")
log_maif.info(command)
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = p.communicate()
if p.returncode == 0:
for line in output[0].decode(encoding='utf-8').split('\n'):
log_maif.info(line)
else:
for line in output[0].decode(encoding='utf-8').split('\n'):
log_maif.error(line)
log_maif.info("Fin du backup full")
return output
I want to run this function in the background into a loop :
for host in list_hosts_sans_doublon:
backup(host) # <-- how to run the whole function in background ?
In ksh, I would have written something like backup $host & with backup a function that takes $host as an argument.
What you are looking for is to run the function in a different thread from what I understand. For this you need to use python thread module.
This is how you start a thread:
import threading
def backup(mystring):
print(mystring)
host="hello"
x = threading.Thread(target=backup, [host])
x.start()
Do what ever you want after this and the thread will run separately.

Revit Python Shell - Change Parameter Group

I'm trying to write a quick script to open a family document, change the parameter group of 2 specified parameters, and then close and save the document. I've done multiple tests and I am able to change the parameter groups of the specified parameters, but the changes of the groups don't save back to the family file. When I open the newly saved family, the parameter groups revert back to their original group.
This is with Revit 2017.2.
The same script, when run in RPS in Revit 2018 will do as desired.
import clr
import os
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import UIApplication
from System.IO import Directory, SearchOption
searchstring = "*.rfa"
dir = r"C:\Users\dboghean\Desktop\vanity\2017"
docs = []
if Directory.Exists(dir):
files = Directory.GetFiles(dir, searchstring, SearchOption.AllDirectories)
for f in files:
name, extension = os.path.splitext(f)
name2, extension2 = os.path.splitext(name)
if extension2:
os.remove(f)
else:
docs.append(f)
else:
print("Directory does not exist")
doc = __revit__.ActiveUIDocument.Document
app = __revit__.Application
uiapp = UIApplication(app)
currentPath = doc.PathName
pgGroup = BuiltInParameterGroup.PG_GRAPHICS
for i in docs:
doc = app.OpenDocumentFile(i)
paramList = [i for i in doc.FamilyManager.Parameters]
t = Transaction(doc, "test")
t.Start()
for i in paramList:
if i.Definition.Name in ["Right Sidesplash Edge line", "Left Sidesplash Edge line"]:
i.Definition.ParameterGroup = pgGroup
t.Commit()
doc.Close(True)
Any ideas?
Thanks!
I can confirm that this happens in Revit 2017. Strange!
A simple way around it is to arbitrarily rename the parameter using doc.FamilyManager.RenameParameter, then rename it back to the original name.
So in your case this would be three additional lines of code after changing the Parameter group:
originalName = i.Definition.Name
doc.FamilyManager.RenameParameter(i, "temp")
doc.FamilyManager.RenameParameter(i, originalName)
Doesnt get to the root problem, but works around it

How to define empty IndexedTables in Julia?

I am unable to define empty IndexedTables, e.g.
using IndexedTables, IndexedTables.Table
t = Table(Columns(a=Int64[],b=String[]),Int64[])
t[1,"a"] = 1
t[1,"b"] = 2
t[1,"c"] = t[1,"a"] + t[1,"b"]
BoundsError: attempt to access 0-element Array{Int64,1} at index [0]
I am aware that creating the IndexedTable with already the data is more efficient that creating an empty one and then insert values, but sometimes you are obliged to go on this way.
Is this a bug ? If so, is there any workaround possible ?
(I already posted this thread on the Julia forum, but so far I had no replies there)
This is probably a bug in IndexedTables.
Inserting into an IndexedTable requires reindexing to access the data. Reindexing is done with flush!.
But flush!(t) fails in the example in the question with the empty t.
Fixing flush! which calls _merge! can be done by:
julia> function IndexedTables._merge!(dst::IndexedTable, src::IndexedTable, f)
if length(dst.index)==0 || isless(dst.index[end], src.index[1])
append!(dst.index, src.index)
append!(dst.data, src.data)
else
# merge to a new copy
new = _merge(dst, src, f)
ln = length(new)
# resize and copy data into dst
resize!(dst.index, ln)
copy!(dst.index, new.index)
resize!(dst.data, ln)
copy!(dst.data, new.data)
end
return dst
end
julia> t[1,"c"] = t[1,"a"] + t[1,"b"]
3
The change is the addition of the length(...) check in the first if.
Of course, a pull request / issue should be opened with IndexedTables.jl. Antonello, will you do this? (or shall I)

Can LLDB data formatters call methods?

I'm debugging a Qt application using LLDB. At a breakpoint I can write
(lldb) p myQString.toUtf8().data()
and see the string contained within myQString, as data() returns char*. I would like to be able to write
(lldb) p myQString
and get the same output. This didn't work for me:
(lldb) type summary add --summary-string "${var.toUtf8().data()}" QString
Is it possible to write a simple formatter like this, or do I need to know the internals of QString and write a python script?
Alternatively, is there another way I should be using LLDB to view QStrings this way?
The following does work.
First, register your summary command:
debugger.HandleCommand('type summary add -F set_sblldbbp.qstring_summary "QString"')
Here is an implementation
def make_string_from_pointer_with_offset(F,OFFS,L):
strval = 'u"'
try:
data_array = F.GetPointeeData(0, L).uint16
for X in range(OFFS, L):
V = data_array[X]
if V == 0:
break
strval += unichr(V)
except:
pass
strval = strval + '"'
return strval.encode('utf-8')
#qt5
def qstring_summary(value, unused):
try:
d = value.GetChildMemberWithName('d')
#have to divide by 2 (size of unsigned short = 2)
offset = d.GetChildMemberWithName('offset').GetValueAsUnsigned() / 2
size = get_max_size(value)
return make_string_from_pointer_with_offset(d, offset, size)
except:
print '?????????????????????????'
return value
def get_max_size(value):
_max_size_ = None
try:
debugger = value.GetTarget().GetDebugger()
_max_size_ = int(lldb.SBDebugger.GetInternalVariableValue('target.max-string-summary-length', debugger.GetInstanceName()).GetStringAtIndex(0))
except:
_max_size_ = 512
return _max_size_
It is expected that what you tried to do won't work. The summary strings feature does not allow calling expressions.
Calling expressions in a debugger is always interesting, in a data formatter more so (if you're in an IDE - say Xcode - formatters run automatically). Every time you stop somewhere, even if you just stepped over one line, all these little expressions would all automatically run over and over again, at a large performance cost - and this is not even taking into account the fact that your data might be in a funny state already and running expressions has the potential to alter it even more, making your debugging sessions trickier than needed.
If the above wall of text still hasn't discouraged you ( :-) ), you want to write a Python formatter, and use the SB API to run your expression. Your value is an SBValue object, which has access to an SBFrame and an SBTarget. The combination of these two allows you to run EvaluateExpression("blah") and get back another SBValue, probably a char* to which you can then ask GetSummary() to get your c-string back.
If, on the other hand, you are now persuaded that running expressions in formatters is suboptimal, the good news is that QString most certainly has to store its data pointer somewhere.. if you find out where that is, you can just write a formatter as ${var.member1.member2.member3.theDataPointer} and obtain the same result!
this is my trial-and-error adaptation of a UTF16 string interpretation lldb script I found online (I apologise that I don't remember the source - and that I can't credit the author)
Note that this is for Qt 4.3.2 and versions close to it - as the handling of the 'data' pointer has since changed between then and Qt 5.x
def QString_SummaryProvider(valobj, internal_dict):
data = valobj.GetChildMemberWithName('d')#.GetPointeeData()
strSize = data.GetChildMemberWithName('size').GetValueAsUnsigned()
newchar = -1
i = 0
s = u'"'
while newchar != 0:
# read next wchar character out of memory
data_val = data.GetChildMemberWithName('data').GetPointeeData(i, 1)
size = data_val.GetByteSize()
e = lldb.SBError()
if size == 1:
newchar = data_val.GetUnsignedInt8(e, 0) # utf-8
elif size == 2:
newchar = data_val.GetUnsignedInt16(e, 0) # utf-16
elif size == 4:
newchar = data_val.GetUnsignedInt32(e, 0) # utf-32
else:
s = s + '<unexpected char size - error parsing QString>'
break
if e.fail:
s = s + '<parse error:' + e.why() + '>'
break
i = i + 1
if i > strSize:
break
# add the character to our string 's'
# print "char2 = %s" % newchar
if newchar != 0:
s = s + unichr(newchar)
s = s + u'"'
return s.encode('utf-8')

Python/Tkinter How to update information in grid

I'm running Python 3.2.2 and writing some code to test sockets. For the ease of testing, I'm using Tkinter to add a GUI interface. What I have yet to figure out is how to update the information in the grid I'm using. I want to update "host2" and "port2" in the functions "change1" and "change3" in the following code:
import socket
from tkinter import *
import tkinter.simpledialog
root = Tk()
root.title("Server")
root.iconbitmap("etc.ico")
root.geometry("350x100+200+200")
frame = Frame(root)
host1 = Label(frame,text="Host: ").grid(row=0,column=0)
port1 = Label(frame,text="Port: ").grid(row=1,column=0)
HOST = 'localhost'
PORT = 11111
STATUS = 'EMPTY'
host2 = Label(frame,text=HOST,width=10).grid(row=0,column=1)
port2 = Label(frame,text=PORT,width=10).grid(row=1,column=1)
status1 = Label(root,text=STATUS)
status1.pack(side=RIGHT,padx=2,pady=2)
def change1():
global HOST
HOST= tkinter.simpledialog.askstring(title="Host",prompt="Enter the IP of the Host.")
host2.grid_forget()
def change3():
global PORT
PORT= tkinter.simpledialog.askinteger(title="Port",prompt="Enter the Port of the IP.")
port2.grid_forget()
def go1():
global HOST
global PORT
home = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
home.bind((HOST, PORT))
home.listen(1)
conn, addr = home.accept()
print (addr)
while 1:
data = conn.recv(1024)
if not data: break
global STATUS
STATUS = data.decode('UTF-8')
conn.send(bytes('Received "Hello World"','UTF-8'))
conn.close()
global status1
status1.pack_forget()
status1.pack(side=RIGHT,padx=2,pady=2)
change = Button(frame, text="Change Host", width=10,command=change1).grid(row=0,column=2)
change2 = Button(frame, text="Change Port", width=10,command=change3).grid(row=1,column=2)
go = Button(frame, text="GO!",command=go1,width =10).grid(row=2,column=2)
frame.pack(side=LEFT)
mainloop()
Any help on the matter would be much appreciated! Thanks!
Your problems begin with this line:
host1 = Label(frame,text="Host: ").grid(row=0,column=0)
What you are doing is creating a label, using grid to place the label on the screen, then assigning host1 the result of the grid() command, which is the empty string. This makes it impossible to later refer to host1 to get a reference to the label.
Instead, you need to save a reference to the label. With that reference you can later change anything you want about the label:
host1 = Label(frame, text="Host: ")
host1.grid(row=0, column=0)
...
if (something_has_changed):
host1.configure(text="Hello, world!")
Take it from someone with over a decade of experience with tk, it's better to separate your widget creation and layout. Your layout will almost certainly change over the course of development and it's much easier to do that when all your layout code is in one place. My layouts may change a lot but my working set of widgets rarely does, so I end up only having to change one block of code rather than dozens of individual lines interleaved with other code.
For example, my code generally looks roughly like this:
labell = tk.Label(...)
label2 = tk.Label(...)
entry1 = tk.Entry(...)
label1.grid(...)
label2.grid(...)
entry1.grid(...)
Of course, I use much better variable names.
First, before going in depth with this problem. I want to highlight out a few things. In this line.
host2 = Label(frame,text=HOST,width=10).grid(row=0,column=1)
I want you to separate the gridding part from the declaration of the variable. Because it will create a No Type object that you cant work with. It will create many problems in the future that may take a lot of your time. If you have any variables structured like this that are not just going to be served as lines of text. Change the structure of that of that variable to the structure that I described above. Anyways, going back to what you where saying but in more depth is that to change the text of the Labels. What I would do if its going to be changed by function is in that function that you are wanting to change the text of the Label. Put in lines like this.
host2['text'] = 'Your New Text'
port2['text'] = 'Your New Text'
# or
host2.configure(text = 'Your New Text')
port2.configure(text = 'Your New Text')
This will change the text of your labels to the newly changed text or In other words replaces the text with the new text.

Resources